A.3*3讨论即可,注意正方形套圆套三角形只有6个点。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=110; 10 int n,ans,a[N]; 11 12 int main(){ 13 scanf("%d",&n); 14 rep(i,1,n) scanf("%d",&a[i]); 15 rep(i,2,n){ 16 if ((a[i-1]==2 && a[i]==3) || (a[i-1]==3 && a[i]==2)){ puts("Infinite"); return 0; } 17 if ((a[i-1]==1 && a[i]==2) || (a[i-1]==2 && a[i]==1)) ans+=3; 18 if ((a[i-1]==1 && a[i]==3) || (a[i-1]==3 && a[i]==1)) ans+=4; 19 if (i>=3 && a[i-2]==3 && a[i-1]==1 && a[i]==2) ans--; 20 } 21 printf("Finite %d ",ans); 22 return 0; 23 }
B.相同字符显然放在一起,先统计一共有几种字符。若一种,直接输出。若两种,若两字符相邻则无解否则直接输出。若三种,若三字符均相邻则无解,否则132或213总有一种可行。若四种,3142即可。四种以上,前一半和后一半间隔着输出即可。如n=6时输出142536。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=1010; 10 char s[N]; 11 int T,n,cnt[N],w[N]; 12 13 int main(){ 14 for (scanf("%d",&T); T--; ){ 15 scanf("%s",s+1); n=strlen(s+1); int d=0; 16 rep(i,0,25) cnt[i]=0; 17 rep(i,1,n) cnt[s[i]-'a']++; 18 rep(i,0,25) if (cnt[i]) w[++d]=i; 19 if (d==1){ puts(s+1); continue; } 20 if (d==2){ 21 if (w[1]+1==w[2]) puts("No answer"); 22 else{ 23 rep(i,1,cnt[w[1]]) putchar(w[1]+'a'); 24 rep(i,1,cnt[w[2]]) putchar(w[2]+'a'); puts(""); 25 } 26 continue; 27 } 28 if (d==3){ 29 if (w[1]+1==w[2]){ 30 if (w[2]+1==w[3]) puts("No answer"); 31 else{ 32 rep(i,1,cnt[w[1]]) putchar(w[1]+'a'); 33 rep(i,1,cnt[w[3]]) putchar(w[3]+'a'); 34 rep(i,1,cnt[w[2]]) putchar(w[2]+'a'); puts(""); 35 } 36 }else{ 37 rep(i,1,cnt[w[2]]) putchar(w[2]+'a'); 38 rep(i,1,cnt[w[1]]) putchar(w[1]+'a'); 39 rep(i,1,cnt[w[3]]) putchar(w[3]+'a'); puts(""); 40 } 41 continue; 42 } 43 if (d==4){ 44 rep(i,1,cnt[w[3]]) putchar(w[3]+'a'); 45 rep(i,1,cnt[w[1]]) putchar(w[1]+'a'); 46 rep(i,1,cnt[w[4]]) putchar(w[4]+'a'); 47 rep(i,1,cnt[w[2]]) putchar(w[2]+'a'); 48 puts(""); 49 continue; 50 } 51 rep(i,1,(d+1)/2){ 52 rep(j,1,cnt[w[i]]) putchar(w[i]+'a'); 53 if (i+(d+1)/2<=d) rep(j,1,cnt[w[i+(d+1)/2]]) putchar(w[i+(d+1)/2]+'a'); 54 } 55 puts(""); 56 } 57 return 0; 58 }
C.二分答案,设二分值为mid,则将i和n-mid+i依次配对,判断配对数是否>=mid。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=400010; 10 int n,z,ans,a[N],b[N]; 11 12 bool chk(int mid){ 13 int res=0; 14 rep(i,1,mid) if (a[n-mid+i]-a[i]>=z) res++; 15 return res>=mid; 16 } 17 18 int main(){ 19 scanf("%d%d",&n,&z); 20 rep(i,1,n) scanf("%d",&a[i]); 21 sort(a+1,a+n+1); int L=0,R=n/2; 22 while (L<R){ 23 int mid=(L+R+1)>>1; 24 if (chk(mid)) L=mid; else R=mid-1; 25 } 26 printf("%d ",L); 27 return 0; 28 }
D.一种方法是,先对每个点BFS出它所在1连通块的大小bel[x],然后再对每个点BFS出它所在0连通块并将块中的点的bel累加起来得到答案。
还有一种是树上DP,f[x][0/1]表示x往下只走0边/先走0边再走1边,的方案数。g[x][0/1]表示x往下只走1边/先走1边再走0边,的方案数。在每个点上枚举有多少以它为路径最高点的合法路径。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=200010; 10 11 int n,p[N],t; 12 ll f[N][2],g[N][2],ans; 13 struct data{int to,nxt,len; }E[N<<1]; 14 void add(int x,int y,int z){t++;E[t].to=y,E[t].nxt=p[x],E[t].len=z,p[x]=t;} 15 16 void dfs(int k,int from){ 17 f[k][0]=1; g[k][0]=1; 18 for (int i=p[k];i;i=E[i].nxt) 19 if (E[i].to!=from){ 20 dfs(E[i].to,k); 21 if (E[i].len==0) f[k][0]+=f[E[i].to][0]; 22 else f[k][1]+=f[E[i].to][0]+f[E[i].to][1]; 23 if (E[i].len==1) g[k][0]+=g[E[i].to][0]; 24 else g[k][1]+=g[E[i].to][0]+g[E[i].to][1]; 25 } 26 for (int i=p[k];i;i=E[i].nxt) 27 if (E[i].to!=from){ 28 int x=f[k][0],y=f[k][1]; 29 if (E[i].len==0) x-=f[E[i].to][0]; 30 else y-=f[E[i].to][0]+f[E[i].to][1]; 31 if (E[i].len==0) ans+=x*g[E[i].to][1]; 32 ans+=x*g[E[i].to][0]; 33 if (E[i].len==1) ans+=y*g[E[i].to][0]; 34 } 35 ans+=f[k][0]+f[k][1]-1; 36 } 37 38 int main(){ 39 scanf("%d",&n); 40 rep(i,2,n){ 41 int x,y,z; scanf("%d%d%d",&x,&y,&z); 42 add(x,y,z),add(y,x,z); 43 } 44 dfs(1,1); cout<<ans<<endl;; 45 return 0; 46 }
E.从小到大插入p,每次以当前p[x]为区间最大值的合法区间数,就是x左边的已插入的连续段和右边已插入的连续段的信息合并。这个可以用set启发式合并支持查询与合并,为了快速寻找某个位置被合并到哪了需要用到并查集,复杂度两个log。
1 #include<set> 2 #include<cstdio> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 using namespace std; 6 7 const int N=4000010; 8 int n,ans,a[N],id[N],fa[N]; 9 set<int>S[N]; 10 11 bool cmp(int x,int y){ return a[x]<a[y]; } 12 int get(int x){ return fa[x]==x ? x : fa[x]=get(fa[x]); } 13 14 int main(){ 15 scanf("%d",&n); 16 rep(i,1,n) scanf("%d",&a[i]),id[i]=fa[i]=i,S[i].insert(a[i]); 17 sort(id+1,id+n+1,cmp); 18 rep(i,1,n){ 19 int x=id[i],p=get(x-1),q=get(x+1); 20 if (x==1 || x==n || a[x-1]>a[x] || a[x+1]>a[x]){ 21 if (x>1 && a[x-1]<a[x]) S[p].insert(a[x]),fa[x]=p; 22 if (x<n && a[x+1]<a[x]) S[q].insert(a[x]),fa[x]=q; 23 continue; 24 } 25 if (S[p].size()>S[q].size()) swap(p,q); 26 set<int>::iterator it; 27 for (it=S[p].begin(); it!=S[p].end(); it++) 28 if (S[q].find(a[x]-(*it))!=S[q].end()) ans++; 29 for (it=S[p].begin(); it!=S[p].end(); it++) S[q].insert(*it); 30 S[q].insert(a[x]); fa[p]=fa[x]=q; 31 } 32 printf("%d ",ans); 33 return 0; 34 }
F.枚举win的时候是第几次拿数以及这个数是几。f[i][j]表示数j作为第i个拿出来的数且前i个数都严格递增的概率。根据这个再要求第i+1个数也为j,再之后的数随便放即可。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=5010,mod=998244353; 7 int n,x,ans,f[N][N],cnt[N],inv[N]; 8 9 int main(){ 10 scanf("%d",&n); inv[1]=1; 11 rep(i,1,n) scanf("%d",&x),cnt[x]++; 12 rep(i,2,n) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; 13 rep(i,1,n){ 14 int s=(i==1); 15 rep(j,1,n){ 16 f[i][j]=1ll*s*cnt[j]%mod*inv[n-i+1]%mod; 17 if (cnt[j]>1) ans=(ans+1ll*f[i][j]*(cnt[j]-1)%mod*inv[n-i]%mod)%mod; 18 s=(s+f[i-1][j])%mod; 19 } 20 } 21 printf("%d ",ans); 22 return 0; 23 }