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;
}
View Code

 

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-n+m)/2);(n>m)

   注意特判无解情况,t-n-m为奇数时,必然无解。

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

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

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

  

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

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

  至于组合数的解释,请参考其他人的题解。(其实是我不会解释

 

 1 #include<cstdio>
 2 #include<cmath>
 3 using namespace std;
 4 inline int read(){
 5     register int ss=0;register char bb=getchar();
 6     while(bb<48||bb>57)bb=getchar();
 7     while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
 8     return ss;    
 9 }
10 inline long long power(long long x,int y,int const mod){
11     long long ans=0;
12     for(;y;y>>=1,x=(x<<1)%mod)
13         if(y&1)ans=(ans+x)%mod;
14     return ans;
15 }
16 int const t=read(),p=read();
17 int n,m,tot;
18 long long prime[15],f[15],invv[15];
19 inline void split(long long x,int lit){
20     for(register int i=2;i<=lit && x^1;++i)
21         if(!(x%i))prime[++tot]=i,x/=i;
22     if(x^1)prime[++tot]=x;
23     return ;
24 }
25 long long exgcd(long long a,long long b,long long &x,long long &y){
26     if(!b)return x=1,y=0,1;
27     long long z=exgcd(b,a%b,x,y),lh=x;
28     x=y,y=lh-a/b*y;
29     return z;
30 }
31 inline long long inv(long long x,long long mod){
32     long long a,b,c=exgcd(x,mod,a,b);
33     if(c^1)return -1;
34     if(a<0)a=a%mod+mod;
35     return a;
36 }
37 inline long long cp(long long x,long long y,long long const mod){
38     if(x<y)return 0;
39     if(!y || x==y)return 1;
40     if(y>x-y)y=x-y;
41     long long a=1,b=1;
42     for(register int i=0;i<y;++i)
43         a=a*(x-i)%mod,b=b*(y-i)%mod;
44     return a*inv(b,mod)%mod;
45 }
46 long long lucas(long long x,long long y,long long  mod){
47     if(x<y)return 0;
48     if(x==y)return 1;
49     return y?cp(x%mod,y%mod,mod)*lucas(x/mod,y/mod,mod)%mod:1;
50 }
51 inline long long china(){
52     long long ans=0;
53     for(register int i=1;i<=tot;++i)
54         ans=(ans+power(p/prime[i],power(invv[i],f[i],p),p))%p;
55     return ans;
56 }
57 inline long long cq(int x,int y){
58     for(register int i=1;i<=tot;++i)
59         f[i]=lucas(x,y,prime[i]);
60     return china();
61 }
62 inline void swap(int &x,int &y){
63     int z=x;
64     x=y,y=z;
65     return ;
66 }
67 signed main(){
68     n=read(),m=read();
69     if(n<m)swap(n,m);
70     split(p,sqrt(p));
71     for(register int i=1;i<=tot;++i)
72         invv[i]=inv(p/prime[i],prime[i]);
73     printf("%lld",cq(t,t-n+m>>1)*cq(t,t-n-m>>1)%p);
74     return 0;
75 }
这是remarkable的代码

 

 

T3.光

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

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

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

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

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

  证明如下:

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

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

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

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

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

  1 #include<bits/stdc++.h>
  2 #define mk(a,b,c) mp(a,mp(b,c))
  3 #define mp(a,b) make_pair(a,b)
  4 #define pb push_back
  5 using namespace std;
  6 int n,m,k;
  7 long long ans=0;
  8 bool v;
  9 vector<int>h[200005],g[200005];
 10 map<pair<int,pair<int,int> >,bool>c;
 11 map<pair<int,int>,bool>kk;
 12 int main()
 13 {
 14     scanf("%d%d%d",&n,&m,&k);int kkk=max(n,m);
 15     for(int i=1;i<=k;i++)
 16     {
 17         int x,y;
 18         scanf("%d%d",&x,&y);
 19         kk[mp(x,y)]=true;
 20         h[x+y].pb(x-y);
 21         g[x-y+kkk].pb(x+y);
 22     }
 23     for(int i=0,x,y;i<=m+1;i++)
 24     {
 25         x=0,y=i;
 26         kk[mp(x,y)]=true;
 27         h[x+y].pb(x-y);
 28         g[x-y+kkk].pb(x+y);
 29         x=n+1;
 30         kk[mp(x,y)]=true;
 31         h[x+y].pb(x-y);
 32         g[x-y+kkk].pb(x+y);
 33     }
 34     for(int i=0,x,y;i<=n+1;i++)
 35     {
 36         x=i,y=0;
 37         kk[mp(x,y)]=true;
 38         h[x+y].pb(x-y);
 39         g[x-y+kkk].pb(x+y);
 40         y=m+1;
 41         kk[mp(x,y)]=true;
 42         h[x+y].pb(x-y);
 43         g[x-y+kkk].pb(x+y);
 44     }
 45     for(int i=0;i<=kkk+kkk+2;i++)
 46         sort(h[i].begin(),h[i].end()),
 47         sort(g[i].begin(),g[i].end());
 48     int x,y,zt,i=0;
 49     string ss;
 50     cin>>x>>y>>ss;
 51     if(ss=="NE")zt=0;
 52     if(ss=="NW")zt=1;
 53     if(ss=="SE")zt=2;
 54     if(ss=="SW")zt=3;
 55     while(!c[mk(x,y,zt)])
 56     {
 57         c[mk(x,y,zt)]=true;i++;
 58         if(zt==0)
 59         {
 60             int cc=*--upper_bound(h[x+y].begin(),h[x+y].end(),x-y),
 61                 xx=(x+y+cc)>>1,yy=(x+y-cc)>>1;
 62             if(i^1)ans+=abs(x-xx);
 63             if((kk[mp(xx+1,yy)]&&kk[mp(xx,yy-1)])
 64             ||(!kk[mp(xx+1,yy)]&&!kk[mp(xx,yy-1)]))
 65             {
 66                 zt=3,x=xx+1,y=yy-1;
 67                 if(i^1)v=true;
 68             }
 69             else if(kk[mp(xx+1,yy)])
 70                 zt=1,x=xx,y=yy-1;
 71             else if(kk[mp(xx,yy-1)])
 72                 zt=2,x=xx+1,y=yy;
 73         }
 74         else if(zt==3)
 75         {
 76             int cc=*upper_bound(h[x+y].begin(),h[x+y].end(),x-y),
 77                 xx=(x+y+cc)>>1,yy=(x+y-cc)>>1;
 78             if(i^1)ans+=abs(x-xx);
 79             if((kk[mp(xx-1,yy)]&&kk[mp(xx,yy+1)])
 80             ||(!kk[mp(xx-1,yy)]&&!kk[mp(xx,yy+1)]))
 81             {
 82                 zt=0,x=xx-1,y=yy+1;
 83                 if(i^1)v=true;
 84             }
 85             else if(kk[mp(xx-1,yy)])
 86                 zt=2,x=xx,y=yy+1;
 87             else if(kk[mp(xx,yy+1)])
 88                 zt=1,x=xx-1,y=yy;
 89         }
 90         else if(zt==1)
 91         {
 92             int cc=*--upper_bound(g[x-y+kkk].begin(),g[x-y+kkk].end(),x+y),
 93                 xx=(x-y+cc)>>1,yy=(cc-x+y)>>1;
 94             if(i^1)ans+=abs(x-xx);
 95             if((kk[mp(xx+1,yy)]&&kk[mp(xx,yy+1)])
 96             ||(!kk[mp(xx+1,yy)]&&!kk[mp(xx,yy+1)]))
 97             {
 98                 zt=2,x=xx+1,y=yy+1;
 99                 if(i^1)v=true;
100             }
101             else if(kk[mp(xx+1,yy)])
102                 zt=0,x=xx,y=yy+1;
103             else if(kk[mp(xx,yy+1)])
104                 zt=3,x=xx+1,y=yy;
105         }
106         else if(zt==2)
107         {
108             int cc=*upper_bound(g[x-y+kkk].begin(),g[x-y+kkk].end(),x+y),
109                 xx=(x-y+cc)>>1,yy=(cc-x+y)>>1;
110             if(i^1)ans+=abs(x-xx);
111             if((kk[mp(xx-1,yy)]&&kk[mp(xx,yy-1)])
112             ||(!kk[mp(xx-1,yy)]&&!kk[mp(xx,yy-1)]))
113             {
114                 zt=1,x=xx-1,y=yy-1;
115                 if(i^1)v=true;
116             }
117             else if(kk[mp(xx+1,yy)])
118                 zt=3,x=xx,y=yy-1;
119             else if(kk[mp(xx,yy+1)])
120                 zt=0,x=xx-1,y=yy;
121         }
122     }
123     printf("%lld\n",v?ans/2:ans);
124     return 0;
125 }
大模拟

 

posted @ 2019-07-22 21:12  tdcp  阅读(280)  评论(5编辑  收藏  举报