连考两场……
上午模拟测试19:
考试过程(忘得差不多了):
读完三道题,T1不会(又想打树形dp……),T2显然二分,T3不可做……还是大概打了一下T1,觉得个‘SZN’有点类似,打挂了……果断弃掉开始搞T2,二分还是很容易的,然后发现我的solve是$n^2$的,就开始想怎么干掉一层循环,想了好久,打了两个贪心,都被对拍干掉了……就这样一直想着‘我能想出来正解’,然后就挂了……最后剩下一个小时的时候才发现‘我想不出来正解’……完戏。因为一直在想怎么用贪心优化第一层循环,也稍微想了想第二层循环的优化,但是没有深入思考(真的没想出来是倍增)。还有很多人用暴力什么的加break,return啥的A掉了(我的倍增还T了好几次……),而我的是纯的$n^2$,没有一点break,return(最后被我及其不要脸地从20分卡到70分)……T3的暴力大概打了40分钟吧(主要是调不出来),拿了10分(重测后25)。最后大脑一片空白,心态崩溃,因为算着最多拿40分,还很有可能爆0……T1瞎调过了样例(其实只是最后的数撞对了)。不过最后还没有想的那么凉(主要是T2骗了50分)
21 | AlpaCa | 10 03:07:22 | 70 03:15:15 | 25 03:07:14 | 105 03:15:15 |
考试总结:
T1考试之后想了想觉得虽然正解不是很好像但是80分的暴力显然啊,我是脑子抽了没想到还想着打树形dp。首先是难度评估不准确,然后是时间分配不合理(千万不要相信‘我能想出正解’这种东西……),最后导致心态爆炸,算起来T1真正好好思考的没几分钟吧……其实考试这种东西,炸就炸吧,考试的时候不要想这些东西,以自己最好的状态拿到自己能拿的分就足够了。不要想着‘我要A一道题’‘我要进rankx’什么的,这种东西多少会对自己有一点影响。
然后就是每道题至少认真思考30分钟之后完全没有思路才可以弃掉,不要想这次T1那么草率,连个暴力都没打。
A. count
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdio> 4 #define LL long long 5 #define MAXN 1000010 6 using namespace std; 7 struct edge 8 { 9 int u,v,nxt; 10 #define u(x) ed[x].u 11 #define v(x) ed[x].v 12 #define n(x) ed[x].nxt 13 }ed[MAXN*2]; 14 int first[MAXN],num_e; 15 #define f(x) first[x] 16 LL C[110][110]; 17 int n,ans; 18 int f[MAXN],size[MAXN]; 19 int que[MAXN*2],head,tail; 20 bool dfs(int x,int fa,int num) 21 { 22 size[x]=1;f[x]=0; 23 for(int i=f(x);i;i=n(i)) 24 if(v(i)!=fa) 25 {if(!dfs(v(i),x,num))return 0;size[x]=size[v(i)];} 26 if(!n(f(x))){f[x]=1;return 1;} 27 head=1,tail=0; 28 for(int i=f(x);i;i=n(i)) 29 if(v(i)!=fa)que[++tail]=f[v(i)]; 30 sort(que+head,que+tail+1); 31 while(head<tail) 32 { 33 if(que[head]==num){head++;continue;} 34 if(que[tail]==num){tail--;continue;} 35 // cout<<x<<endl; 36 if(que[head]+que[tail]==num-1)head++,tail--,f[x]=-1; 37 if(que[head]+que[tail]>num-1) 38 { 39 if(f[x])return 0; 40 else f[x]=que[tail],tail--; 41 } 42 if(que[head]+que[tail]<num-1)que[head]+=que[tail],tail--; 43 } 44 if(head==tail) 45 { 46 if(que[head]>num)return 0; 47 if(que[head]==num)return 1; 48 else 49 { 50 if(f[x])return 0; 51 else f[x]=que[head]; 52 } 53 } 54 if(f[x]==-1)f[x]=0; 55 return 1; 56 } 57 void getC() 58 { 59 C[0][0]=1; 60 for(int i=1;i<=100;i++) 61 { 62 C[i][0]=1; 63 for(int j=1;j<=i;j++) 64 C[i][j]=C[i-1][j-1]+C[i-1][j]; 65 } 66 } 67 inline int read(); 68 inline void add(int u,int v); 69 signed main() 70 { 71 n=read(); 72 int x,y;getC(); 73 for(int i=1;i<n;i++) 74 x=read(),y=read(), 75 add(x,y),add(y,x); 76 if(n<=100) 77 { 78 LL ans=0; 79 for(int k=1;k<=n;k++) 80 if(n%k==0) 81 { 82 if(dfs(1,0,n/k)) 83 { 84 // cout<<k<<endl; 85 ans++; 86 } 87 } 88 printf("%lld\n",ans); 89 return 0; 90 } 91 puts("2"); 92 } 93 inline int read() 94 { 95 int s=0,f=1;char a=getchar(); 96 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 97 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 98 return s*f; 99 } 100 inline void add(int u,int v) 101 { 102 ++num_e; 103 u(num_e)=u; 104 v(num_e)=v; 105 n(num_e)=f(u); 106 f(u)=num_e; 107 }考试代码
暴力:
首先可以发现如果将 N 分成 D 这么大的块如果可以的话,方案只有一种。
枚举块数,直接dfs就好了,如果当前点size等于1+所有未分开的子树的size和。如果当前点size==d return ;否则return 0;最后看根节点size判断。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 struct edge 5 { 6 int u,v,nxt; 7 #define u(x) ed[x].u 8 #define v(x) ed[x].v 9 #define n(x) ed[x].nxt 10 }ed[2100000*2]; 11 int first[2100000],num_e; 12 #define f(x) first[x] 13 int n,size[2100000]; 14 bool dfs(int x,int fa,int num) 15 { 16 size[x]=1; 17 for(int i=f(x);i;i=n(i)) 18 if(v(i)!=fa) 19 { 20 if(dfs(v(i),x,num))continue; 21 else size[x]+=size[v(i)]; 22 } 23 if(size[x]==num)return 1; 24 else return 0; 25 } 26 inline int read(); 27 inline void add(int u,int v); 28 signed main() 29 { 30 n=read();int x,y; 31 for(int i=1;i<n;i++) 32 x=read(),y=read(), 33 add(x,y),add(y,x); 34 int ans=0; 35 for(int i=1;i<=n;i++) 36 if(n%i==0) 37 { 38 if(dfs(1,0,n/i))ans++; 39 } 40 printf("%d\n",ans); 41 } 42 inline int read() 43 { 44 int s=0,f=1;char a=getchar(); 45 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 46 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 47 return s*f; 48 } 49 inline void add(int u,int v) 50 { 51 ++num_e; 52 u(num_e)=u; 53 v(num_e)=v; 54 n(num_e)=f(u); 55 f(u)=num_e; 56 }暴力
正解:
(已经弄成有根树)我们可以发现一个可行的方案的最浅的那个点为根的子树的 SIZE 一定可以整除 D。
Check 就不用 N 去 check 了,如果有 N/D 个节点的 SIZE 可以整除 D,那么就可行。
1 #include<iostream> 2 #include<cstdio> 3 #define re register 4 #define co const 5 using namespace std; 6 struct edge 7 { 8 int u,v,nxt; 9 #define u(x) ed[x].u 10 #define v(x) ed[x].v 11 #define n(x) ed[x].nxt 12 }ed[2100000*2]; 13 int first[2100000],num_e; 14 #define f(x) first[x] 15 int n,size[2100000]; 16 void dfs(re int x,re int fa) 17 { 18 size[x]=1; 19 for(int i=f(x);i;i=n(i)) 20 if(v(i)!=fa)dfs(v(i),x),size[x]+=size[v(i)]; 21 } 22 inline int read(); 23 inline void add(int u,int v); 24 signed main() 25 { 26 n=read();int x,y; 27 for(int i=1;i<n;i++) 28 x=read(),y=read(), 29 add(x,y),add(y,x); 30 dfs(1,0); 31 int ans=0,res=0; 32 for(int i=1;i<=n;i++) 33 if(n%i==0) 34 { 35 res=0; 36 for(int j=1;j<=n;j++) 37 if(size[j]%i==0) 38 { 39 res++; 40 if(res>=n/i){ans++;break;} 41 } 42 } 43 printf("%d\n",ans); 44 } 45 inline int read() 46 { 47 int s=0,f=1;char a=getchar(); 48 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 49 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 50 return s*f; 51 } 52 inline void add(int u,int v) 53 { 54 ++num_e; 55 u(num_e)=u; 56 v(num_e)=v; 57 n(num_e)=f(u); 58 f(u)=num_e; 59 }View Code
B. Dinner
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<ctime> 5 #define LL long long 6 #define MAXN 100010 7 #define INF 0x7fffffff 8 using namespace std; 9 int n,m,maxt,pos,sumt; 10 int t[MAXN*2]; 11 int que[MAXN*3],head,tail; 12 bool v[MAXN*2]; 13 bool solve2(int ti) 14 { 15 // memset(v,0,sizeof(v)); 16 int ans=0x7fffffff; 17 for(int st=1;st<=min(n,500);st++) 18 // if(!v[st]&&!v[st+n]) 19 { 20 if(st>n)st-=n; 21 int now=0;int res=0; 22 for(int i=st;i<st+n;i++) 23 { 24 if(now+t[i]>ti){res++,now=0;} 25 if(res>=ans)break; 26 now+=t[i]; 27 } 28 if(now)res++; 29 // if(res<ans) cout<<st<<":"<<" "<<res<<endl; 30 ans=min(ans,res); 31 } 32 // cout<<ti<<" "<<ans<<endl; 33 return ans<=m; 34 } 35 bool solve(int ti) 36 { 37 int st=0,now=INF,sum=0;head=1,tail=0; 38 if(pos<n)pos+=n; 39 for(st=pos;st;st--){sum+=t[st];if(sum>ti)break;}st++; 40 // st=pos; 41 /* for(int i=1;i<n*2;i++) 42 { 43 sum+=t[i];que[++tail]=t[i]; 44 while(sum>ti)sum-=que[head++]; 45 if(ti-sum<now)now=ti-sum,st=head; 46 }*/ 47 if(st>n)st-=n; 48 // cout<<st<<":"<<endl; 49 now=0;int res=0; 50 for(int i=st;i<st+n;i++) 51 { 52 if(now+t[i]>ti){res++,now=0;} 53 now+=t[i]; 54 } 55 if(now)res++; 56 // cout<<ti<<" "<<now<<" "<<res<<endl; 57 return res<=m; 58 } 59 inline int read(); 60 signed main() 61 { 62 // freopen("in.txt","r",stdin); 63 // freopen("1.out","w",stdout); 64 65 n=read();m=read(); 66 for(int i=1;i<=n;i++) 67 { 68 t[i]=read();sumt+=t[i]; 69 if(t[i]>maxt)maxt=t[i],pos=i; 70 } 71 for(int i=1;i<=n;i++)t[i+n]=t[i]; 72 // int tem=read();solve(tem); 73 // solve(1457); 74 int l=maxt,r=sumt,mid,ans=INF; 75 while(l<=r) 76 { 77 mid=(l+r)>>1; 78 // bool flag=(n<=5000?(solve2(mid)):(solve(mid))); 79 bool flag=solve2(mid); 80 if(flag)ans=min(ans,mid),r=mid-1;//!!!!!!!!!!!!! 81 else l=mid+1; 82 if(clock()/1000>960)break; 83 } 84 printf("%d\n",ans); 85 } 86 inline int read() 87 { 88 int s=0,f=1;char a=getchar(); 89 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 90 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 91 return s*f; 92 }考试代码
考虑二分答案,check 本质上就是看圆环能否分成至多 m 段,并且每段的和小于
等于当且 check 的答案。可以用 st[i][ j]表示从 i 开始跳 2^j 段(每段的长度不超过二
分的答案)最远能跳到哪里。然后利用这个数组就可以 O(logn)的时间去计算从 i 跳 m
段最远能跳到哪里,最后暴力看每个位置作为起点,能跳到哪里,只要能越过自己,
就表明可以。总的时间复杂度 O(nlog^2n)。
倍增预处理,二分 check。
好吧其实并没有什么可说的,不过不知道为啥我的倍增跑这么慢……
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<ctime> 5 #define LL long long 6 #define MAXN 100010 7 #define re register 8 #define co const 9 #define INF 0x7fffffff 10 using namespace std; 11 int n,m,maxt,pos,sumt; 12 int t[MAXN*2]; 13 int f[100010][21]; 14 bool solve2(co int ti) 15 { 16 // cout<<"tiiiiiiiiiiiiii: "<<ti<<endl; 17 memset(f,0x7f,sizeof(f)); 18 int sum=0,j=1; 19 for(int i=1;i<=n;i++) 20 { 21 sum-=t[i-1]; 22 for(;j<=n*3;j++) 23 if(sum+t[j]>ti){f[i][0]=j-1;break;} 24 else sum+=t[j]; 25 } 26 for(int i=1;i<=n;i++)f[i+n][0]=f[i][0]+n; 27 for(int i=1;i<=n*2;i++)if(f[i][0]>n*2)f[i][0]=n*2; 28 for(int i=1;i<=15;i++) 29 for(re int j=1;j<=n*2;j++) 30 { 31 if(f[j][i-1]==n*2)f[j][i]=n*2; 32 else if(f[f[j][i-1]+1][i-1]>=n*2)f[j][i]=n*2; 33 else f[j][i]=f[f[j][i-1]+1][i-1]; 34 if(f[j][i]>n*2)f[j][i]=n*2; 35 } 36 int ans=0x7fffffff,tem=m; 37 for(int st=1;st<=n;st++) 38 { 39 int now=st;tem=m; 40 for(int j=15;j>=0;j--) 41 if((1<<j)<=tem) 42 { 43 now=f[now][j]+1,tem-=(1<<j); 44 if(now>=st+n)return 1; 45 if(now==1)return 1; 46 } 47 if(now>=st+n)return 1; 48 } 49 return 0; 50 } 51 inline int read(); 52 signed main() 53 { 54 // freopen("in.txt","r",stdin); 55 // freopen("1.out","w",stdout); 56 57 n=read();m=read(); 58 for(re int i=1;i<=n;i++) 59 { 60 t[i]=read();sumt+=t[i]; 61 if(t[i]>maxt)maxt=t[i],pos=i; 62 } 63 for(re int i=1;i<=n*2;i++)t[i+n]=t[i]; 64 int l=maxt,r=sumt,mid,ans=INF; 65 while(l<=r) 66 { 67 mid=(l+r)>>1; 68 if(solve2(mid))ans=min(ans,mid),r=mid-1;//!!!!!!!!!!!!! 69 else l=mid+1; 70 } 71 printf("%d\n",ans); 72 } 73 inline int read() 74 { 75 int s=0,f=1;char a=getchar(); 76 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 77 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 78 return s*f; 79 }View Code
C. chess
1 #include<iostream> 2 #include<cstdio> 3 #define LL long long 4 using namespace std; 5 int m,n; 6 char map[65][65]; 7 int sx,sy,ex,ey; 8 LL ans=0x7ffffffffff,sum[100000]; 9 bool v[55][55],vkg[1000000]; 10 #define min(a,b) ((a)<(b)?(a):(b)) 11 inline int read(); 12 void dfs(int nx,int ny,int res,int kg) 13 { 14 // cout<<nx<<" "<<ny<<" "<<res<<" "<<kg<<endl; 15 if(map[nx][ny]==0)kg++; 16 if(res>ans+1)return; 17 if(nx==ex&&ny==ey) 18 { 19 if(res-1<ans) 20 { 21 ans=min(ans,res-1);sum[ans]=1; 22 } 23 else if(res-1==ans) 24 { 25 if(ans!=0)sum[ans]++; 26 } 27 return; 28 } 29 v[nx][ny]=1; 30 if(!v[nx-1][ny-2]&&nx-1>=1&&ny-2>=1&&map[nx-1][ny-2]!=2)dfs(nx-1,ny-2,res+(map[nx-1][ny-2]!=1),kg); 31 if(!v[nx-1][ny+2]&&nx-1>=1&&ny+2<=m&&map[nx-1][ny+2]!=2)dfs(nx-1,ny+2,res+(map[nx-1][ny+2]!=1),kg); 32 if(!v[nx-2][ny-1]&&nx-2>=1&&ny-1>=1&&map[nx-2][ny-1]!=2)dfs(nx-2,ny-1,res+(map[nx-2][ny-1]!=1),kg); 33 if(!v[nx-2][ny+1]&&nx-2>=1&&ny+1<=m&&map[nx-2][ny+1]!=2)dfs(nx-2,ny+1,res+(map[nx-2][ny+1]!=1),kg); 34 35 if(!v[nx+1][ny-2]&&nx+1<=n&&ny-2>=1&&map[nx+1][ny-2]!=2)dfs(nx+1,ny-2,res+(map[nx+1][ny-2]!=1),kg); 36 if(!v[nx+1][ny+2]&&nx+1<=n&&ny+2<=m&&map[nx+1][ny+2]!=2)dfs(nx+1,ny+2,res+(map[nx+1][ny+2]!=1),kg); 37 if(!v[nx+2][ny-1]&&nx+2<=n&&ny-1>=1&&map[nx+2][ny-1]!=2)dfs(nx+2,ny-1,res+(map[nx+2][ny-1]!=1),kg); 38 if(!v[nx+2][ny+1]&&nx+2<=n&&ny+1<=m&&map[nx+2][ny+1]!=2)dfs(nx+2,ny+1,res+(map[nx+2][ny+1]!=1),kg); 39 v[nx][ny]=0; 40 } 41 signed main() 42 { 43 n=read(),m=read(); 44 for(int i=1;i<=n;i++) 45 { 46 for(int j=1;j<=m;j++) 47 { 48 map[i][j]=read(); 49 if(map[i][j]==3)sx=i,sy=j; 50 else if(map[i][j]==4)ex=i,ey=j; 51 } 52 } 53 dfs(sx,sy,0,0); 54 if(ans==0x7ffffffffff){puts("-1");} 55 else printf("%lld\n%lld\n",ans,sum[ans]); 56 } 57 inline int read() 58 { 59 int s=0,f=1;char a=getchar(); 60 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 61 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 62 return s*f; 63 }考试代码
暴力:dfs暴搜即可,期望得分25。
正解:
最短路问题,建图也比较明显,边权有 0 和 1,然块弄出来,然后这个块可以走到
的空格之间两两边权后按照题目要求求方案数的话只需要缩边就可以了,因为代价为
0 的边不算方案数。具体做法可以把代价为 0 的连通为 1.
方案数的统计比较恶心,好像Dj和弗洛伊德好像都统计不了方案数,只能用SPFA了。
值得注意的是重边的处理,因为方案数是按空格统计的,所以重边会导致答案变多,一种处理方法是先用邻接矩阵存储,最后建边。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 #define LL long long 6 #define int LL 7 using namespace std; 8 struct edge 9 { 10 int u,v,w,it; 11 #define u(x) ed[x].u 12 #define v(x) ed[x].v 13 #define w(x) ed[x].w 14 #define n(x) ed[x].it 15 }ed[10000000*2]; 16 int first[50001],num_e; 17 #define f(x) first[x] 18 int m,n; 19 char map[105][105]; 20 int sx,sy,ex,ey; 21 int bh[105][105]; 22 int px[9]={0,1, 1,2, 2,-1,-1,-2,-2}; 23 int py[9]={0,2,-2,1,-1, 2,-2, 1,-1}; 24 bool pd(int x,int y){return x>0&&y>0&&x<=n&&y<=m&&map[x][y]!=2;} 25 bool edg[5010][5010]; 26 bool v[50001]; 27 int dis[5010],count[5010]; 28 void spfa(int st) 29 { 30 memset(dis,0x7f,sizeof(dis)); 31 memset(count,0,sizeof(count)); 32 queue<int> q;v[st]=1; 33 dis[st]=0;q.push(st);count[st]=1; 34 while(!q.empty()) 35 { 36 int x=q.front();q.pop();v[x]=0; 37 for(int i=f(x);i;i=n(i)) 38 { 39 if(dis[v(i)]>dis[x]+w(i)) 40 { 41 dis[v(i)]=dis[x]+w(i); 42 count[v(i)]=count[x]; 43 if(!v[v(i)])q.push(v(i)),v[v(i)]=1; 44 } 45 else if(dis[v(i)]==dis[x]+w(i)) 46 { 47 count[v(i)]+=count[x]; 48 if(!v[v(i)])q.push(v(i)),v[v(i)]=1; 49 } 50 } 51 } 52 } 53 bool ooo[2510],ved[55][55]; 54 void dfs(int x,int y) 55 { 56 if(ved[x][y])return; 57 ved[x][y]=1; 58 for(int i=1;i<=8;i++) 59 { 60 int p1=x+px[i],p2=y+py[i]; 61 if(pd(p1,p2)&&map[p1][p2]==1)dfs(p1,p2); 62 if(pd(p1,p2)&&map[p1][p2]!=1)ooo[bh[p1][p2]]=1; 63 } 64 } 65 #define min(a,b) ((a)<(b)?(a):(b)) 66 inline int get(int i,int j){return (i-1)*m+j;} 67 inline void add(int u,int v,int w); 68 inline void fz(int &x,int y){x=y;} 69 inline int read(); 70 signed main() 71 { 72 // freopen("chess2.in","r",stdin); 73 74 n=read(),m=read(); 75 for(int i=1;i<=n;i++) 76 { 77 for(int j=1;j<=m;j++) 78 { 79 map[i][j]=read(); 80 if(map[i][j]==3)sx=i,sy=j; 81 else if(map[i][j]==4)ex=i,ey=j; 82 } 83 } 84 for(int i=1;i<=n;i++) 85 for(int j=1;j<=m;j++) 86 bh[i][j]=get(i,j); 87 for(int i=1;i<=n;i++) 88 for(int j=1;j<=m;j++) 89 if(map[i][j]!=1) 90 { 91 for(int k=1;k<=8;k++) 92 if(pd(i+px[k],j+py[k])&&map[i+px[k]][j+py[k]]!=1) 93 edg[bh[i][j]][bh[i+px[k]][j+py[k]]]=1; 94 } 95 else 96 { 97 memset(ooo,0,sizeof(ooo));dfs(i,j); 98 for(int k=1;k<=n*m;k++) 99 if(ooo[k]&&k!=bh[ex][ey]) 100 for(int l=1;l<=n*m;l++) 101 if(l!=k&&ooo[l]) 102 edg[k][l]=1; 103 } 104 for(int i=1;i<=n*m;i++) 105 for(int j=1;j<=m*n;j++) 106 if(i!=j&&edg[i][j])add(i,j,1); 107 spfa(bh[sx][sy]); 108 if(dis[bh[ex][ey]]==dis[0]){puts("-1");return 0;} 109 printf("%lld\n%lld\n",dis[bh[ex][ey]]-1,count[bh[ex][ey]]); 110 } 111 inline int read() 112 { 113 int s=0,f=1;char a=getchar(); 114 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 115 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 116 return s*f; 117 } 118 inline void add(int u,int v,int w) 119 { 120 ++num_e; 121 u(num_e)=u; 122 v(num_e)=v; 123 w(num_e)=w; 124 n(num_e)=f(u); 125 f(u)=num_e; 126 }View Code
晚上模拟测试20: