7.22 NOIP模拟7

又是炸掉的一次考试

T1.方程的解

  本次考试最容易骗分的一道题,但是由于T2花的时间太多,我竟然连a+b=c都没判。。暴力掉了40分。

  首先a+b=c,只有一组解。

  然后是a=1,b=1,答案是c-1,不解释。

  对于最大的数据,我们可以用exgcd求出一组特解,之后的通解为x+(b/gcd)*k, y+(a/gcd)*k.

  求出正整数解的个数即可。

  注意有很多特判,慢慢调试就好(改这题的时间比我改T3的时间都长)

#include<bits/stdc++.h>
#define m 65535
#define int long long
using namespace std;
int t,a,b,c,x,y;
long long ans;
int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    int gcd=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
    return gcd;
}
main()
{
    scanf("%lld",&t);
    while(t--)
    {
        ans=0;
        scanf("%lld%lld%lld",&a,&b,&c);
        if(a+b==c&&a>=1&&b>=1)
        {
            puts("1");
            continue;
        }
        if(a<0&&b<0&&c<0)
            a=-a,b=-b,c=-c;
        if(a==1&&b==1)
        {
            ans=c-1;
            if(ans>0&&ans<=65535)
            {
                printf("%lld\n",ans);
                continue;
            }
            if(ans<=0)
                puts("0");
            if(ans>m)
                puts("ZenMeZheMeDuo");
            continue;
        }
        if(t<=100&&a<=1000&&a>=1&&b<=1000&&b>=1&&c>=1&&c<=1000)
        {
            for(int i=1;i<=1000;i++)
                for(int j=1;j<=1000;j++)
                {
                    if(a*i+b*j>c)break;
                    if(a*i+b*j==c)ans++;
                }
            if(ans>m)puts("ZenMeZheMeDuo");
            else printf("%lld\n",ans);
            continue;
        }
        if(a==0&&b==0)
        {
            if(c==0)puts("ZenMeZheMeDuo");
            else puts("0");
            continue;
        }
        if(a==0)
        {
            if(b>0)
            {
                if(c>0&&(!(c%b)))puts("ZenMeZheMeDuo");
                else puts("0");
            }
            if(b<0)
            {
                if(c<0&&(!(c%b)))puts("ZenMeZheMeDuo");
                else puts("0");
            }
            continue;
        }
        if(b==0)
        {
            if(a>0)
            {
                if(c>0&&(!(c%a)))puts("ZenMeZheMeDuo");
                else puts("0");
            }
            if(a<0)
            {
                if(c<0&&(!(c%a)))puts("ZenMeZheMeDuo");
                else puts("0");
            }
            continue;
        }
        if((a<0&&b<0&&c>=0)||(a>0&&b>0&&c<=0))
        {
            puts("0");
            continue;
        }
        if(a<0&&b<0&&c<0)
            a=-a,b=-b,c=-c;
        int gcd=exgcd(a,b,x,y);
        if(c%gcd)
        {
            puts("0");
            continue;
        }
        if(a*b<0)
        {
            puts("ZenMeZheMeDuo");
            continue;
        }
        int k=c/gcd,xx=b/gcd,yy=a/gcd;
        x*=k,y*=k;
        if(xx<0)
            xx=-xx,yy=-yy;
        if(x<=0)
        {
            int xxx=x/xx+1;
            x+=xxx*xx,y-=yy*xxx;
        }
        if(y<=0)
        {
            int xxx=y/yy+1;
            x-=xx*xxx,y+=yy*xxx;
        }
        while(x<=0)
            x+=xx,y-=yy;
        while(y<=0)
            x-=xx,y+=yy;
        if(!x||!y)
        {
            puts("0");
            continue;
        }
        if(x/y<0||y/x<0)
        {
            puts("0");
            continue;
        }
        int aa=x/xx+1,bb=y/yy+1;
        if(!(x%xx))aa--;
        if(!(y%yy))bb--;
        ans=max(aa,bb);
        if(ans>m)puts("ZenMeZheMeDuo");
        else printf("%lld\n",ans);
    }
    return 0;
}

T2.visit

  本场考试最可惜的一道题,打出正解,却因为答案为0的特判wa(改一个字符,70分->AC)

  考试的时候先打了个n^3dp,然后开始找规律

  10,5,5 = C(10,5)*C(10,0);    
  10,4,4 = C(10,5)*C(10,1);    10,4,6=C(10,4)*C(10,0);
  10,3,3 = C(10,5)*C(10,2);    10,3,5=C(10,4)*C(10,1);        10,3,7=C(10,3)*C(10,0);
  10,2,2 = C(10,5)*C(10,3);    10,2,4=C(10,4)*C(10,2);        10,2,6=C(10,3)*C(10,1);        10,2,8=C(10,2)*C(10,0);
  10,1,1 = C(10,5)*C(10,4);
  10,0,0 = C(10,5)*C(10,5);

  这个表我没有打完,但是我感觉已经很显然了,ans=C(t,(t-n-m)/2)*C(t,t/2-abs(n-m)/2);

   然后我终于理解了数据范围最后,mod为若干质数乘积的意思。。。

  恩,然后我就开始手推crt,码码码,大概一个小时调完了,和dp对了几个点,感觉没啥问题,没打对拍放心的去看T3了。

  考后发现自己打了个这个:

  

if(((t%(n+m))&1))
    {
        puts("0");
        return 0;
    }

  ???????????我干了啥?把%改成-,AC。一个特判卡掉30分,我。。。。

  代码可能有些难看,忍忍就好(考场上现推的crt,现码的lucas)

  至于组合数的解释,请参考其他人的题解。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 int t,mod,n,m,kk,pp[50];
 5 long long ans,js[1000005],r[50];
 6 long long qpow(long long x,long long y,long long p)
 7 {
 8     long long ans=1;
 9     while(y)
10     {
11         if(y&1)ans=ans*x%p;
12         x=x*x%p;
13         y>>=1;
14     }
15     return ans;
16 }
17 long long C(long long x,long long y,long long p)
18 {
19     js[0]=1;
20     for(int i=1;i<=x;i++)
21     {
22         js[i]=js[i-1]*i%p;
23     }
24     return js[x]*qpow(js[y],p-2,p)%p*qpow(js[x-y],p-2,p)%p;
25 }
26 long long crt()
27 {
28     long long mm=mod,ans=0;
29     for(int i=1;i<=kk;i++)
30     {
31         long long c=mm/pp[i];
32         long long ni=qpow(c,pp[i]-2,pp[i]);
33         ans=(ans+r[i]*ni%mod*c%mod)%mod;
34     }
35     return ans;
36 }
37 long long lu(long long x,long long y,long long p)
38 {
39     long long ans=1;
40     while(x&&y)
41     {
42         long long a=x%p,b=y%p;
43         x/=p,y/=p;
44         if(a<b)return 0;
45         ans=ans*C(a,b,p)%p;
46     }
47     return ans%p;
48 }
49 bool check(long long x)
50 {
51     if(x==1)return false;
52     long long sq=sqrt(x);
53     for(int i=2;i<=sq;i++)
54         if(!(x%i))
55             return false;
56     return true;
57 }
58 long long L(long long x,long long y)
59 {
60     for(int i=1;i<=kk;i++)
61     {
62         int k=pp[i];
63         r[i]=lu(x,y,k);
64     }
65     return crt();
66 }
67 main()
68 {
69     scanf("%lld%lld%lld%lld",&t,&mod,&n,&m);
70     int sq=sqrt(mod)+1;
71     for(int i=1;i<=sq;i++)
72     {
73         if(!(mod%i))
74         {
75             if(check(i))
76             {
77                 pp[++kk]=i;
78             }
79             if((i!=mod/i)&&check(mod/i))
80             {
81                 pp[++kk]=mod/i;
82             }
83         }
84     }
85     if(n<0)n=-n;
86     if(m<0)m=-m;
87     if(n+m!=0)
88     if(((t-(n+m))&1))
89     {
90         puts("0");
91         return 0;
92     }
93     ans=L(t,t/2-(abs(n-m)/2))*L(t,(t-n-m)/2)%mod;
94     printf("%lld",ans);
95     return 0;
96 }

T3.光

  没想到一道模拟题卡掉了我50分。。。暴力都打错了,骗到20分,考完后发现加clock等一大堆特判可以卡到80分。

  正解就是模拟,但是优化了一下。首先,在原来的基础上,可以直接考虑到当前状态的终点:答案显然具有单调性,可以二分答案。

  在同一种状态中,横纵坐标之和或差必然不变,因此我们可以将黑块存进保存坐标之和或差的vector中,给每个vector排序后二分答案。

  但是我们似乎忽略了一个问题:如何统计答案?

  一个非常简单却不好想的结论:若一个块被经过,则光线必然只穿过他的一条对角线。

  证明如下:

  我们给每两个相邻的方块染上不同的颜色,则同一种状态的光线只经过同种颜色的方块。而除了反向反射的两种状态,另外两种反射方式必然从一种颜色的方块变成另一种,即,经过右下->左上对角线和右上->左下对角线的光线穿过的方块颜色必不相同,所以同一方块不可能被穿过两条对角线。

  既然如此,那么就又有一个非常显然的结论:一个方块最多被经过两次,两次穿过同一对角线且方向相反。

  那么一个方块被经过两次的条件呢?当且仅当发生了反向的反射。同样,若发生了反向的反射,反向光线会将原光线的所有路径重走一遍,因此,一旦发生反向反射,所有被经历的方块都会被穿过两次。否则,每个方块仅被穿过一次。

  因此,我们可以记录是否发生了反向的反射,若发生了,最后统计的答案数/2。计算每种状态的贡献时,只需将起始节点和终点的横(纵)坐标相减即可。

  注意反射情况十分复杂,分类讨论即可。为了方便,多调几个STL挺好的。

#include<bits/stdc++.h>
#define mk(a,b,c) make_pair(a,make_pair(b,c))
using namespace std;
const int zx[4]={-1,-1,1,1},zy[4]={1,-1,1,-1};
int n,m,k;
long long ans=0;
bool vv;
vector<int>h[200005],g[200005];
map<pair<int,pair<int,int> >,bool>c;
map<pair<int,int>,bool>kk;
int main()
{
    scanf("%d%d%d",&n,&m,&k);int kkk=max(n,m);
    for(int i=1;i<=k;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        kk[make_pair(x,y)]=true;
        h[x+y].push_back(x-y);
        g[x-y+kkk].push_back(x+y);
    }
    for(int i=0,x,y;i<=m+1;i++)
    {
        x=0,y=i;
        kk[make_pair(x,y)]=true;
        h[x+y].push_back(x-y);
        g[x-y+kkk].push_back(x+y);
        x=n+1;
        kk[make_pair(x,y)]=true;
        h[x+y].push_back(x-y);
        g[x-y+kkk].push_back(x+y);
    }
    for(int i=0,x,y;i<=n+1;i++)
    {
        x=i,y=0;
        kk[make_pair(x,y)]=true;
        h[x+y].push_back(x-y);
        g[x-y+kkk].push_back(x+y);
        y=m+1;
        kk[make_pair(x,y)]=true;
        h[x+y].push_back(x-y);
        g[x-y+kkk].push_back(x+y);
    }
    for(int i=0;i<=kkk+kkk+2;i++)
        sort(h[i].begin(),h[i].end()),
        sort(g[i].begin(),g[i].end());
    int x,y,zt;
    string ss;
    cin>>x>>y>>ss;
    if(ss=="NE")
        zt=0;
    if(ss=="NW")
        zt=1;
    if(ss=="SE")
        zt=2;
    if(ss=="SW")
        zt=3;
    if(zt==0)
    {
        int cc=*--upper_bound(h[x+y].begin(),h[x+y].end(),x-y),xx=(x+y+cc)>>1,yy=(x+y-cc)>>1;
        if((kk.count(make_pair(xx+1,yy))&&kk.count(make_pair(xx,yy-1)))||((!kk.count(make_pair(xx+1,yy)))&&(!kk.count(make_pair(xx,yy-1)))))
        {
            zt=3,x=xx+1,y=yy-1;
        }
        else if(kk.count(make_pair(xx+1,yy)))
        {
            zt=1,x=xx,y=yy-1;
        }
        else if(kk.count(make_pair(xx,yy-1)))
        {
            zt=2,x=xx+1,y=yy;
        }
    }
    else if(zt==3)
    {
        int cc=*upper_bound(h[x+y].begin(),h[x+y].end(),x-y),xx=(x+y+cc)>>1,yy=(x+y-cc)>>1;
        if((kk.count(make_pair(xx-1,yy))&&kk.count(make_pair(xx,yy+1)))||((!kk.count(make_pair(xx-1,yy)))&&(!kk.count(make_pair(xx,yy+1)))))
        {
            zt=0,x=xx-1,y=yy+1;
        }
        else if(kk.count(make_pair(xx-1,yy)))
        {
            zt=2,x=xx,y=yy+1;
        }
        else if(kk.count(make_pair(xx,yy+1)))
        {
            zt=1,x=xx-1,y=yy;
        }
    }
    else if(zt==1)
    {
        int cc=*--upper_bound(g[x-y+kkk].begin(),g[x-y+kkk].end(),x+y),xx=(x-y+cc)>>1,yy=(cc-x+y)>>1;
        if((kk.count(make_pair(xx+1,yy))&&kk.count(make_pair(xx,yy+1)))||((!kk.count(make_pair(xx+1,yy)))&&(!kk.count(make_pair(xx,yy+1)))))
        {
            zt=2,x=xx+1,y=yy+1;
        }
        else if(kk.count(make_pair(xx+1,yy)))
        {
            zt=0,x=xx,y=yy+1;
        }
        else if(kk.count(make_pair(xx,yy+1)))
        {
            zt=3,x=xx+1,y=yy;
        }
    }
    else if(zt==2)
    {
        int cc=*upper_bound(g[x-y+kkk].begin(),g[x-y+kkk].end(),x+y),xx=(x-y+cc)>>1,yy=(cc-x+y)>>1;
        if((kk.count(make_pair(xx-1,yy))&&kk.count(make_pair(xx,yy-1)))||((!kk.count(make_pair(xx-1,yy)))&&(!kk.count(make_pair(xx,yy-1)))))
        {
            zt=1,x=xx-1,y=yy-1;
        }
        else if(kk.count(make_pair(xx+1,yy)))
        {
            zt=3,x=xx,y=yy-1;
        }
        else if(kk.count(make_pair(xx,yy+1)))
        {
            zt=0,x=xx-1,y=yy;
        }
    }
    while(!c.count(mk(x,y,zt)))
    {
        c[mk(x,y,zt)]=true;
        if(zt==0)
        {
            int cc=*--upper_bound(h[x+y].begin(),h[x+y].end(),x-y),xx=(x+y+cc)>>1,yy=(x+y-cc)>>1;
            ans+=abs(x-xx);
            if((kk.count(make_pair(xx+1,yy))&&kk.count(make_pair(xx,yy-1)))||((!kk.count(make_pair(xx+1,yy)))&&(!kk.count(make_pair(xx,yy-1)))))
            {
                zt=3,x=xx+1,y=yy-1,vv=true;
            }
            else if(kk.count(make_pair(xx+1,yy)))
            {
                zt=1,x=xx,y=yy-1;
            }
            else if(kk.count(make_pair(xx,yy-1)))
            {
                zt=2,x=xx+1,y=yy;
            }
        }
        else if(zt==3)
        {
            int cc=*upper_bound(h[x+y].begin(),h[x+y].end(),x-y),xx=(x+y+cc)>>1,yy=(x+y-cc)>>1;
            ans+=abs(x-xx);
            if((kk.count(make_pair(xx-1,yy))&&kk.count(make_pair(xx,yy+1)))||((!kk.count(make_pair(xx-1,yy)))&&(!kk.count(make_pair(xx,yy+1)))))
            {
                zt=0,x=xx-1,y=yy+1,vv=true;
            }
            else if(kk.count(make_pair(xx-1,yy)))
            {
                zt=2,x=xx,y=yy+1;
            }
            else if(kk.count(make_pair(xx,yy+1)))
            {
                zt=1,x=xx-1,y=yy;
            }
        }
        else if(zt==1)
        {
            int cc=*--upper_bound(g[x-y+kkk].begin(),g[x-y+kkk].end(),x+y),xx=(x-y+cc)>>1,yy=(cc-x+y)>>1;
            ans+=abs(x-xx);
            if((kk.count(make_pair(xx+1,yy))&&kk.count(make_pair(xx,yy+1)))||((!kk.count(make_pair(xx+1,yy)))&&(!kk.count(make_pair(xx,yy+1)))))
            {
                zt=2,x=xx+1,y=yy+1,vv=true;
            }
            else if(kk.count(make_pair(xx+1,yy)))
            {
                zt=0,x=xx,y=yy+1;
            }
            else if(kk.count(make_pair(xx,yy+1)))
            {
                zt=3,x=xx+1,y=yy;
            }
        }
        else if(zt==2)
        {
            int cc=*upper_bound(g[x-y+kkk].begin(),g[x-y+kkk].end(),x+y),xx=(x-y+cc)>>1,yy=(cc-x+y)>>1;
            ans+=abs(x-xx);
            if((kk.count(make_pair(xx-1,yy))&&kk.count(make_pair(xx,yy-1)))||((!kk.count(make_pair(xx-1,yy)))&&(!kk.count(make_pair(xx,yy-1)))))
            {
                zt=1,x=xx-1,y=yy-1,vv=true;
            }
            else if(kk.count(make_pair(xx+1,yy)))
            {
                zt=3,x=xx,y=yy-1;
            }
            else if(kk.count(make_pair(xx,yy+1)))
            {
                zt=0,x=xx-1,y=yy;
            }
        }
    }
    printf("%lld\n",vv?ans/2:ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hzoi-cbx/p/11228437.html
今日推荐