2022春训第二场

2022/3/25 23:22:38

本文主要是介绍2022春训第二场,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

春训第二场。

之前实在是太懒了,开学说要好好练,到现在还是几乎没做什么。从这场开始努力!

[D]

分析:

两点在移动过程中的距离可以算一下,化简后是关于\(t\)的一次或二次函数(\(a\)>=0)。然后简单判断就可以了;但是一直卡在第21个点过不去。
找了一篇来拍,结果拍到一个点竟然是那篇错了。总之思路挺简单,就摆在这吧。

代码如下
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define db double
db const EPS=1e-10;
int const N=1e5+5,M=1005;
int n,d1,d2;
int dis2(int x1,int y1,int x2,int y2) {return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);}

int geta(int tx1,int ty1,int tx2,int ty2,int x1,int y1,int x2,int y2)
    {return ((x1-x2)-(tx1-tx2)) * ((x1-x2)-(tx1-tx2))
          + ((y1-y2)-(ty1-ty2)) * ((y1-y2)-(ty1-ty2));}

int getb(int tx1,int ty1,int tx2,int ty2,int x1,int y1,int x2,int y2)
    {return ( 2*(x1-x2)*(tx1-tx2) - 2*(tx1-tx2)*(tx1-tx2) )
          + ( 2*(y1-y2)*(ty1-ty2) - 2*(ty1-ty2)*(ty1-ty2) );}

int getc(int tx1,int ty1,int tx2,int ty2,int x1,int y1,int x2,int y2)
    {return (tx1-tx2)*(tx1-tx2) + (ty1-ty2)*(ty1-ty2);}

db cal(int a,int b,int c,db t)
    {return (db)a*t*t + (db)b*t + c;}

db getmint(int a,int b,int c)
{
    db p = (-0.5) * (db)b / (db)a ;
    if(a==0) return (b>=0)?0:1;//
    else // a>0
    {
        if(a*b >= 0) return 0; // p<=0
        else if(b <= (-2)*a) return 1; // p>=1
        else return p;
    }
}

db getmaxt(int a,int b,int c)
{
    // db p = (-1.0) * b / (2.0 * a);
    if(a==0) return (b>=0)?1:0;//
    else // a>0
    {
        if(a*b >= 0) return 1; // p<=0
        else if(b <= (-2)*a) return 0; // p>=1
        // else return (cal(a,b,c,0)-cal(a,b,c,1)>EPS)?0:1;
        else return (0 > a+b)?0:1;
    }
}

int main()
{
    scanf("%d%d%d",&n,&d1,&d2);
    d1 = d1*d1; d2 = d2*d2; //平方
    int x1,y1,x2,y2,tx1,ty1,tx2,ty2;
    scanf("%d%d%d%d",&tx1,&ty1,&tx2,&ty2);
    int ans=0; bool fl=1; //fl=1:可以
    for(int i=2;i<=n;i++)
    {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        int a=geta(tx1,ty1,tx2,ty2,x1,y1,x2,y2);
        int b=getb(tx1,ty1,tx2,ty2,x1,y1,x2,y2);
        int c=getc(tx1,ty1,tx2,ty2,x1,y1,x2,y2);
        printf("i=%d a=%d\n",i,a);

        db mint=getmint(a,b,c), maxt=getmaxt(a,b,c);
        db mind=cal(a,b,c,mint), maxd=cal(a,b,c,maxt);
        // printf("i=%d d1=%d d2=%d maxt=%.2lf mint=%.2lf maxd=%.2lf mind=%.2lf\n",i,d1,d2,maxt,mint,maxd,mind);
        
        if(mind - d1 <= EPS) // mind <= d1
        {
            if(mint - maxt < EPS) // mint < maxt
            {
                if(fl || cal(a,b,c,0) - d2 > EPS) ans++, fl = ((maxd - d2) > EPS),
                                            printf("i=%d\n",i);
                else fl |= ((maxd - d2) > EPS);
            }
            else // mint >= maxt
            {
                if(fl || maxd - d2 > EPS) ans++, fl = ((cal(a,b,c,1) - d2) > EPS),
                                            printf("i=%d\n",i);
                // else fl=0;
                else fl |= ((maxd - d2) > EPS);
            }
        }
        else fl |= (maxd - d2 > EPS);
        tx1 = x1; ty1 = y1;  tx2 = x2; ty2 = y2;
    }
    printf("%d\n",ans);
    return 0;
}

[E]

分析:

搜索所有情况,要判断是不是每个点都出现了。用哈希的方法很巧妙:给每个点赋一个随机数 \(b[i]\) ,一种情况的哈希值就是它里面出现的点的 \(b\) 的异或和。

所有点都出现的情况就是所有 \(b[i]\) 的异或和。

没见过的哈希做法,值得记录。

代码如下
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pb push_back
int const bs=137,md=998244353;
int const N=2e5+5,M=10;
int n,m,k,num[M],ans; // num[i]:出度为i的节点的个数
ll tot,b[N]; // 每个点的一个随机数(哈希值)
ll hsh[M][M]; // hsh[i][j]:出度为i的节点都走第j小的边,按顺序得到的去向点的哈希值
vector<ll>can; // n排列的哈希值
struct Ed{
    int to,w;
    Ed(int t=0,int ww=0){to=t; w=ww;}
    bool operator < (const Ed &b) const
        {return w < b.w;}
};
struct Nd{
    int id,out;
    vector<Ed>ed;
    bool operator < (const Nd &b) const
        {return out < b.out;}
}a[N];
ull Rand()
{
    // ull ret=rand();
    // ret <<= 10;
    // ret ^= 12345;
    // return ret*rand();
    return rand();
}
void dfs(int t,ll h)
{
    if(t<=k)
    {
        for(int i=1;i<=t;i++)
            dfs(t+1,h^hsh[t][i]);
    }
    else
    {
        if(h == tot) ans++;
        return;
    }
}
int main()
{
    srand(time(0));
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) a[i].id=i;
    for(int i=1,u,v,w;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        a[u].out++; a[u].ed.pb(Ed(v,w));
    }
    for(int i=1;i<=n;i++) 
        sort(a[i].ed.begin(), a[i].ed.end()), num[a[i].out]++;

    for(int i=1;i<=n;i++) b[i]=Rand(), tot^=b[i];

    for(int p=1;p<=n;p++)
    {
        int t = a[p].out;
        for(int j=1;j<=t;j++) // 第j小的边
        {
            int to = a[p].ed[j-1].to;
            hsh[t][j] ^= b[to];
        }
    }
    dfs(1,0);
    printf("%d\n",ans);
    return 0;
}


这篇关于2022春训第二场的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程