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-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 }
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 }