6.17 NOI 模拟
阅读原文时间:2023年07月10日阅读:2

\(T1\ crime\)

计算几何\(+\)最短路,我的写法很麻烦

比较无脑,直接扫一遍判断能否连接即可,需要特别判断对角线的情况

#include<bits/stdc++.h>
#define double long double
#define MAXN 200005
using namespace std;
const double g=9.80665,eps=1e-6,addx=1e-10;
int head[MAXN],nxt[MAXN<<1],to[MAXN<<1],tot;
int dis[MAXN],h[25][25];
int dx,dy,w,v,lx,ly;
void put(double x)
{
    printf("%.3f\n",x);
}
bool ck(int x,int y,int xx,int yy,double Sx,double Sy,double t)
{
    double Vx=Sx/t;
    double Vy=(Sy+0.5*g*t*t)/t;
    if(x>xx)
    {
       double Sumx=sqrt(1.0*abs(x-xx)*w*abs(x-xx)*w);
       double Sumy=sqrt(1.0*abs(y-yy)*w*abs(y-yy)*w);
       for(int i=x;i>xx;i--)
       {
           double disx=(x-i)*w*1.0+0.5*w;
           double disy=disx/Sumx*Sumy;
           double nowy=(y-1)*w+0.5*w+(yy>y?1:(yy==y?0:-1))*disy+addx;
           int id=(ceil)(nowy/w);
           double nowt=sqrt(pow(disx,2)+pow(disy,2))/Vx;
           double peoh=h[x][y]+Vy*nowt-0.5*g*nowt*nowt;
           double zah;
           if(fabs(1.0*(id-1)*w-nowy)<eps)
           {
              zah=1.0*max({h[i][id],h[i][id-1],h[i-1][id],h[i-1][id-1]});
           }
           else
           {
              zah=1.0*max(h[i][id],h[i-1][id]);
           }
           if(peoh<zah) return false;
       }
    }
    if(x<xx)
    {
       double Sumx=sqrt(1.0*abs(x-xx)*w*abs(x-xx)*w);
       double Sumy=sqrt(1.0*abs(y-yy)*w*abs(y-yy)*w);
       for(int i=x;i<xx;i++)
       {
           double disx=(i-x)*w*1.0+0.5*w;
           double disy=disx/Sumx*Sumy;
           double nowy=(y-1)*w+0.5*w+(yy>y?1:(yy==y?0:-1))*disy+addx;
           int id=(ceil)(nowy/w);
           double nowt=sqrt(pow(disx,2)+pow(disy,2))/Vx;
           double peoh=h[x][y]+Vy*nowt-0.5*g*nowt*nowt;
           double zah;
           if(fabs(1.0*(id-1)*w-nowy)<eps)
           {
              zah=1.0*max({h[i][id],h[i][id-1],h[i+1][id],h[i+1][id-1]});
           }
           else
           {
              zah=1.0*max(h[i][id],h[i+1][id]);
           }
           if(peoh<zah) return false;
       }
    }
    if(y>yy)
    {
       double Sumx=sqrt(1.0*abs(x-xx)*w*abs(x-xx)*w);
       double Sumy=sqrt(1.0*abs(y-yy)*w*abs(y-yy)*w);
       for(int i=y;i>yy;i--)
       {
           double disy=(y-i)*w*1.0+0.5*w;
           double disx=(disy/Sumy)*Sumx;
           double nowx=(x-1)*w+0.5*w+(xx>x?1:(xx==x?0:-1))*disx+addx;
           int id=(ceil)(nowx/w);
           double nowt=sqrt(pow(disx,2)+pow(disy,2))/Vx;
           double peoh=h[x][y]+Vy*nowt-0.5*g*nowt*nowt;
           double zah;
           if(fabs(1.0*(id-1)*w-nowx)<eps)
           {
              zah=max({h[id][i],h[id-1][i],h[id][i-1],h[id-1][i-1]});
           }
           else
           {
              zah=max(h[id][i],h[id][i-1]);
           }
           if(peoh<zah) return false;
       }
    }
    if(y<yy)
    {
       double Sumx=sqrt(1.0*abs(x-xx)*w*abs(x-xx)*w);
       double Sumy=sqrt(1.0*abs(y-yy)*w*abs(y-yy)*w);
       for(int i=y;i<yy;i++)
       {
           double disy=(i-y)*w*1.0+0.5*w;
           double disx=(disy/Sumy)*Sumx;
           double nowx=(x-1)*w+0.5*w+(xx>x?1:(xx==x?0:-1))*disx+addx;
           int id=(ceil)(nowx/w);
           double nowt=sqrt(pow(disx,2)+pow(disy,2))/Vx;
           double peoh=h[x][y]+Vy*nowt-0.5*g*nowt*nowt;
           double zah;
           if(fabs(1.0*(id-1)*w-nowx)<eps)
           {

              zah=max({h[id][i],h[id-1][i],h[id][i+1],h[id-1][i+1]});
           }
           else
           {
              zah=max(h[id][i],h[id][i+1]);
           }
           if(peoh<zah) return false;
       }
    }
    return true;
}
bool check(int x,int y,int xx,int yy)
{
    double Sx=sqrt(pow((abs(x-xx)*w),2)+pow((abs(y-yy)*w),2));
    double Sy=h[xx][yy]-h[x][y];
    double det=pow(v*v-g*Sy,2)-g*g*Sy*Sy-g*g*Sx*Sx;
    if(det<0) return false;
    double t1=sqrt((v*v-Sy*g+sqrt(det))/(0.5*g*g));
    double t2=sqrt((v*v-Sy*g-sqrt(det))/(0.5*g*g));
    return ck(x,y,xx,yy,Sx,Sy,t1)|ck(x,y,xx,yy,Sx,Sy,t2);
}
int id(int x,int y)
{
    return (x-1)*dy+y;
}
void add(int u,int v)
{
    tot++;
    to[tot]=v;
    nxt[tot]=head[u];
    head[u]=tot;
}
void bfs()
{
    queue<int>q;
    memset(dis,-1,sizeof(dis));
    q.push(id(lx,ly));
    dis[id(lx,ly)]=0;
    while(q.size())
    {
        int now=q.front();
        q.pop();
        for(int i=head[now];i;i=nxt[i])
        {
            int y=to[i];
            if(dis[y]==-1)
            {
               dis[y]=dis[now]+1;
               q.push(y);
            }
        }
    }
}
int main()
{
    scanf("%d%d%d%d%d%d",&dx,&dy,&w,&v,&lx,&ly);
    for(int i=1;i<=dy;i++)
    {
        for(int j=1;j<=dx;j++)
        {
            scanf("%d",&h[j][i]);
        }
    }
    for(int i=1;i<=dy;i++)
    {
        for(int j=1;j<=dx;j++)
        {
            for(int i1=1;i1<=dy;i1++)
            {
                for(int j1=1;j1<=dx;j1++)
                {
                    if(i==i1&&j==j1) continue;
                    if(check(j,i,j1,i1))
                    {
                       add(id(j,i),id(j1,i1));
                    }
                }
            }
        }
    }
    bfs();
    for(int i=1;i<=dy;i++)
    {
        for(int j=1;j<=dx;j++)
        {
            if(dis[id(j,i)]==-1) cout<<"X ";
            else cout<<dis[id(j,i)]<<" ";
        }
        cout<<"\n";
    }
}

\(T2\ circle\)

猜结论的二次剩余题 \(kill\ me\)

这道题是一个纯纯的结论题

\(bz\)掏出了三个结论:

\(Sit_1:\)

\[x^2+y^2\equiv r\mod p
\]

我们记 \(Num(r,p)\)

\[p=\prod p_i^{k_i}
\\
Num(r,p)=\prod\limits_{}^i Num(r,p_i)
\]

其实考场上靠直觉能猜到的

\(Sit_2:\)

\(r\ne 0\) 值一样,可以打个表观察一下

\[Num(r,p)=\frac{p\times p-Num(0,p)}{p-1}
\]

\(Sit_3:\)

如果 \(-1\) 有在\(\mod p\)二次剩余 \(Num(0,p)=2\times p-1\)

否则 \(Num(0,p)=1\)

一般这种结论题代码都比较简单了

#include<bits/stdc++.h>
#define int long long
#define MAXN 10000005
using namespace std;
int pri[MAXN+5],val[MAXN+5],Mp[MAXN+5],cnt,p,r;
bool vis[MAXN+5];
int my_pow(int a,int b,int p)
{
    int res=1;
    while(b)
    {
        if(b&1)
        {
            res=(res*a)%p;
        }
        a=(a*a)%p;
        b>>=1;
    }
    return res;
}
void Init()
{
    for(int i=2;i<=MAXN;i++)
    {
        if(!vis[i])
        {
            pri[++cnt]=i;
            if(my_pow(i-1,(i-1)/2,i)==1) val[i]=(2*i-1);
            else val[i]=1;
            Mp[i]=i;
        }
        for(int j=1;j<=cnt&&i*pri[j]<=MAXN;j++)
        {
            vis[i*pri[j]]=true;
            Mp[i*pri[j]]=max(Mp[i],pri[j]);
            if(i%pri[j]==0) break;
        }
    }
}
int Num(int r,int p)
{
    if(r==0) return val[p];
    return (p*p-val[p])/(p-1);
}
// 1 5 0
int dfs(int now)
{
    if(now==1) return 1;
    int x=now,pr=Mp[now];
    while(x%pr==0) x/=pr;
    return Num(r%Mp[now],Mp[now])*dfs(x);
}
void sol()
{
    scanf("%lld%lld",&p,&r);
    cout<<dfs(p)<<"\n";
}
int T;
signed main()
{
    scanf("%lld",&T);
    Init();
    while(T--) sol();
}

\(T3\ crystal\)

和曾经的一道\(CF\)的题有点像

\(\mod 998244353\) 其实感觉像是在提示误导 \(FWT\)

\(a\oplus b=c,a\oplus c=b1\)

我们前\(n-1\)个数任选都不能大于最后选的数的 \(m\) 的话,就可以直接乘法原理了

这就和 \(CF\) 那道题先解除一些数位的限制一样。

考虑,枚举 \(a_p\) 和 \(m_p\) 的最短 \(LCP\), 然后我们这个数系数为 \(1\),其余的数系数相乘即可

具体的,我们只需要让第 \(i\) 位是 \(0\),并且有一个位置 \(p\),\(a_p\) 的第 \(i\) 位是 \(1\) 就可以统计答案了

\(dp[j][k][l]\) 表示第 \(j\) 个数,第 \(i\) 位异或起来为 \(k\) ,有没有钦定 \(p\) 的方案数

考虑 \(m_j\) 第 \(i\) 位为 \(1\),\(a_j\) 可以选 \(0/1\),选 \(0\) 的话贡献的系数是 \(2^i\) ,选 \(1\) 贡献的系数是 \(m\& (2^i-1)+1\),如果确定这一位的话,系数是 \(1\)

#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define MAXN 200005
using namespace std;
const int mod=998244353;
int n,Ans,dat[MAXN];
int dp[2][2][2];
signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&dat[i]);
        Ans^=dat[i];
    }
    Ans=!Ans;
    int Xor=0;
    for(int i=31;i>=0;i--)
    {
        memset(dp,0,sizeof(dp));
        dp[0][0][0]=1;
        for(int j=1;j<=n;j++)
        {
            int now=(j&1);
            int pre=(now^1);
            Xor^=(dat[j]>>(i+1));
            if(dat[j]>>i&1)
            {
               for(int k=0;k<=1;k++)
               {
                   for(int l=0;l<=1;l++)
                   {
                      (dp[now][k^1][l]=dp[pre][k][l]*((dat[j]&(1<<i)-1)+1)%mod)%=mod;
                   }
               }
               for(int k=0;k<=1;k++)
               {
                   (dp[now][k][1]+=dp[pre][k][0]+(ull)(dp[pre][k][1]<<i)%mod)%=mod;
               }
            }
            else
            {
                for(int k=0;k<=1;k++)
                {
                    for(int l=0;l<=1;l++)
                    {
                       (dp[now][k][l]=dp[pre][k][l]*((dat[j]&(1<<i)-1)+1)%mod)%=mod;
                    }
                }
            }
        }
        if(Xor) continue;
        //3 1 2 3
        Ans=(Ans+dp[n&1][0][1])%mod;
    }
    cout<<Ans<<"\n";
}