8.13<1>题解
为什么多了个<1>呢,因为要一天两场了,真让人兴奋^_^,才怪
考场想不出来,考后迅速AC,考场上想不到,想到了还否定自己,我以后要是再在考场上想出了贪心,或者二分答案,我一定先打出来,我xwd的flag就立这了
T1
就考了个不知道算什么玩意的东西,想分成联通块,肯定是某个子树,若联通块大小为$d$,只要有$\frac{n}{d}$个子树的大小是$d$的倍数即可,前提是$d$是$n$的因子,先跑出来每颗子树的大小,然后$O(n^2)$$O(\frac{n^2}{2})$$O(logn)$,大概都可过,当然$O(n^2)$可能有点悬
1 #include<bits/stdc++.h> 2 #include<iostream> 3 #include<cstdio> 4 #define maxn 1000100 5 using namespace std; 6 int n,js,ans=2; 7 int head[maxn],to[maxn*2],xia[maxn*2],size[maxn],pd[maxn]; 8 void add(int x,int y) 9 { 10 to[++js]=y; xia[js]=head[x]; head[x]=js; 11 } 12 void dfs(int x) 13 { 14 size[x]=1; pd[x]=1; 15 for(int i=head[x];i;i=xia[i]) 16 { 17 int ls=to[i]; 18 if(!pd[ls]) {dfs(ls); size[x]+=size[ls];} 19 } 20 } 21 int main() 22 { 23 scanf("%d",&n); 24 for(int i=1;i<n;++i) 25 { 26 int u,v; scanf("%d%d",&u,&v); 27 add(u,v); add(v,u); 28 } 29 dfs(1); 30 for(int i=2;i<=n/2;++i) 31 { 32 if(n%i) continue; 33 int jl=0; 34 for(int j=1;j<=n;++j) 35 if(!(size[j]%i)) jl++; 36 if(jl==n/i) ans++; 37 } 38 printf("%d\n",ans); 39 return 0; 40 }
T2
考场上想到了二分答案,自己脑子抽抽,觉得自己不对,然后就随便选了一个我觉得对的答案?怕是有毛病,用$check$函数,$check$了一个答案,然后就华丽丽的死了,正解就二分然后$check$就好了,关于枚举断点,只需要在1到1可跳到的最远点之间作出选择就可以了,因为后面的点作为断点和前面某个点做断点,在他这又断开了答案是一样的
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #define maxn 50010 6 using namespace std; 7 int n,m,bz,l,r,mj; 8 int a[maxn*2],q[maxn*2]; 9 inline int read() 10 { 11 int e=0; char ch=getchar(); 12 while(ch<'0'||ch>'9') ch=getchar(); 13 while(ch>='0'&&ch<='9') {e=(e<<3)+(e<<1)+(ch^48); ch=getchar();} 14 return e; 15 } 16 bool check(int x) 17 { 18 mj=upper_bound(a+1,a+2*n+1,x)-a; 19 //mj=n; 20 for(int i=1;i<=mj;++i) 21 { 22 int tot=0,da=0,js=0; 23 int j=i; 24 while(j<=i+n-1) 25 { 26 j=upper_bound(a+1,a+2*n+1,a[j-1]+x)-a; js++; 27 if(js>m) break; 28 } 29 if(js<=m) return 1; 30 } 31 return 0; 32 } 33 int main() 34 { 35 n=read(); m=read(); 36 for(int i=1;i<=n;++i) {q[i]=read(); r+=q[i]; l=max(l,q[i]); a[i]=q[i]+a[i-1];} 37 for(int i=n+1;i<=2*n;++i) {q[i]=q[i-n]; a[i]=q[i]+a[i-1];} 38 while(l<r) 39 { 40 int mid=(l+r)>>1; 41 if(check(mid)) r=mid; 42 else l=mid+1; 43 } 44 printf("%d\n",l); 45 return 0; 46 }
T3
考场上不知道自己在干什么,打了一个多小时,已经调完了,发现自己思路完全不对,甚至题都没申清的那一刻,心态炸裂,当场不想调,就那样了,实际上就先把能到达的点之间连边,然后把到达敌人的边缩掉,跑最短路记录方案就可以了
1 //给能跳到的点之间连边 2 //连边是O(nm)的 3 //边权为0的缩掉,重边对bfs无影响 4 //最后的连向终点的边权当作一,给答案减一即可,不然会被缩掉 5 //跑最短路,记录方案数用bfs实现,SPFA可打 6 //松弛的时候顺便记录方案 7 //一个点建8条边,最多2500个点,大概最多20000条边 8 #include<iostream> 9 #include<cstring> 10 #include<cstdio> 11 #include<queue> 12 #define int long long 13 #define maxn 55 14 #define maxm 41000 15 #define bh(i,j) ((i-1)*m+j) 16 using namespace std; 17 int n,m,qd,zd,js,j; 18 int head[maxn*maxn],to[maxm],xia[maxm],w[maxm]; 19 int h[maxn*maxn],t[maxm],x[maxm];//重建之后边权均为1 20 int v[maxn*maxn],pd[maxn*maxn],pre[maxn*maxn]; 21 int dis[maxn*maxn],tot[maxn*maxn]; 22 int a[maxn][maxn]; 23 void add(int x,int y,int z) 24 { 25 to[++js]=y; xia[js]=head[x]; w[js]=z; head[x]=js; 26 } 27 void Add(int a,int b) 28 { 29 t[++j]=b; x[j]=h[a]; h[a]=j; 30 } 31 void sou(int q,int z) 32 { 33 v[z]=1; 34 for(int i=head[z];i;i=xia[i]) 35 { 36 int ls=to[i]; 37 if(v[ls]) continue; 38 if(w[i]) 39 { 40 if(!pd[ls]) {Add(q,ls); pd[ls]=1;} 41 } 42 else sou(q,ls); 43 } 44 } 45 void SPFA(int u) 46 { 47 memset(dis,0x7f,sizeof(dis)); 48 queue <int> s; dis[u]=0; tot[u]=1; v[u]=1; s.push(u); 49 while(s.size()) 50 { 51 int ls=s.front(); s.pop(); 52 for(int i=h[ls];i;i=x[i]) 53 { 54 if(dis[ls]+1==dis[t[i]]) tot[t[i]]+=tot[ls]; 55 else if(dis[ls]+1<dis[t[i]]) 56 { 57 pre[t[i]]=ls; 58 dis[t[i]]=dis[ls]+1; 59 tot[t[i]]=tot[ls]; 60 if(!v[t[i]]) {s.push(t[i]); v[t[i]]=1;} 61 } 62 } 63 v[ls]=0; 64 } 65 } 66 signed main() 67 { 68 scanf("%lld%lld",&n,&m); 69 for(int i=1;i<=n;++i) 70 for(int j=1;j<=m;++j) 71 { 72 scanf("%lld",&a[i][j]); 73 if(a[i][j]==3) qd=bh(i,j); 74 if(a[i][j]==4) zd=bh(i,j); 75 } 76 for(int i=1;i<=n;++i) 77 for(int j=1;j<=m;++j) 78 { 79 if(a[i][j]==2) continue; 80 int num=bh(i,j); 81 if(i+2<=n&&j+1<=m&&a[i+2][j+1]!=2)//i+2 j+1 82 { 83 int pos=bh(i+2,j+1); 84 if(a[i+2][j+1]==1) add(num,pos,0); 85 else add(num,pos,1); 86 } 87 if(i+2<=n&&j-1>=1&&a[i+2][j-1]!=2)//i+2 j-1 88 { 89 int pos=bh(i+2,j-1); 90 if(a[i+2][j-1]==1) add(num,pos,0); 91 else add(num,pos,1); 92 } 93 if(i-2>=1&&j+1<=m&&a[i-2][j+1]!=2)//i-2 j+1 94 { 95 int pos=bh(i-2,j+1); 96 if(a[i-2][j+1]==1) add(num,pos,0); 97 else add(num,pos,1); 98 } 99 if(i-2>=1&&j-1>=1&&a[i-2][j-1]!=2)//i-2 j-1 100 { 101 int pos=bh(i-2,j-1); 102 if(a[i-2][j-1]==1) add(num,pos,0); 103 else add(num,pos,1); 104 } 105 if(i+1<=n&&j+2<=m&&a[i+1][j+2]!=2)//i+1 j+2 106 { 107 int pos=bh(i+1,j+2); 108 if(a[i+1][j+2]==1) add(num,pos,0); 109 else add(num,pos,1); 110 } 111 if(i+1<=n&&j-2>=1&&a[i+1][j-2]!=2)//i+1 j-2 112 { 113 int pos=bh(i+1,j-2); 114 if(a[i+1][j-2]==1) add(num,pos,0); 115 else add(num,pos,1); 116 } 117 if(i-1>=1&&j+2<=m&&a[i-1][j+2]!=2)//i-1 j+2 118 { 119 int pos=bh(i-1,j+2); 120 if(a[i-1][j+2]==1) add(num,pos,0); 121 else add(num,pos,1); 122 } 123 if(i-1>=1&&j-2>=1&&a[i-1][j-2]!=2)//i-1 j-2 124 { 125 int pos=bh(i-1,j-2); 126 if(a[i-1][j-2]==1) add(num,pos,0); 127 else add(num,pos,1); 128 } 129 } 130 for(int i=1;i<=n;++i) 131 for(int j=1;j<=m;++j) 132 { 133 if(a[i][j]==1||a[i][j]==2) continue; 134 int num=bh(i,j); sou(num,num); 135 memset(v,0,sizeof(v)); memset(pd,0,sizeof(pd)); 136 } 137 SPFA(qd); 138 if(tot[zd]==0) printf("-1\n"); 139 else printf("%lld\n%lld\n",dis[zd]-1,tot[zd]); 140 return 0; 141 }