Educational Codeforces Round 64 (Div. 2)

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

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

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

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

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 }
F
原文地址:https://www.cnblogs.com/HocRiser/p/10801724.html