2019CCPC秦皇岛自我反省&部分题解

练了一年半了,第一次打CCPC,险些把队友坑了打铁,最后也是3题危险捡了块铜。

非常水的点双连通,我居然不相信自己去相信板子,唉,结果整来整去,本来半个小时能出的题,整到了3个小时,大失误呀,不然就可以去弄其他题了,对自己的表现太失望了,给自己记一大过。然后导致了策略失误,稀里糊涂的时间久过去了,不然感觉我们队还是能再出3题的。

可惜可惜,自己的这些大赛的经验还是不足,但相信这不会成为拖累自己队伍的后腿,发现问题就要及时调整,在赛场上还是要坚信自己所想到的,不用太苛求于模板形式。

有些急躁,但心态还是挺好,下次多喝点水,急的时候就去尿尿冷静一下。

之前思维题都由鲲鲲和+1很快就想出来了,想不出来就没得法子,自己在思维上明显退步了,接下来除了算法的学习,更重要的思维也不能忘了,自己去补一补。

之后几场不知道会怎么样,未来不可想,现在犹可抓,好好把握接下来不多的时间。

Stand by,Stand by.

1004 就看是不是只包含2和5

 1 #include<cstdio>
 2 bool judge(int n){
 3     while(n>1){
 4         if(n%5==0) n/=5;
 5         else if(n%2==0) n/=2;
 6         else return false;
 7     }
 8     return true;
 9 }
10 int main(){
11     int t,n;
12     scanf("%d",&t);
13     while(t--){
14         scanf("%d",&n);
15         if(judge(n)) printf("No
");
16         else printf("Yes
");
17     }
18     return 0;
19 } 
签到

1006 就看每个环的贡献,就这个sb了,套了个点双的板子,发现错误没及时改。后来重现时是单组测试,所以把多组去了

 1 #include<cstdio>
 2 #include<stack>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int N=5e5+11,M=5e5+11;
 7 const ll md=998244353;
 8 struct Side{
 9     int v,ne;
10     Side(){}
11     Side(int v,int ne):v(v),ne(ne){}
12 }S[M<<1];
13 Side sta[M];
14 int n,sn,dn,bn,tn,head[N],dfn[N],low[N],bin[N],bsi[N];
15 ll cf2[M];
16 void init(){
17     sn=dn=bn=tn=0;
18     for(int i=0;i<=n;i++){
19         head[i]=-1;
20         dfn[i]=bin[i]=0;
21     }
22 }
23 void add(int u,int v){
24     S[sn].v=v;
25     S[sn].ne=head[u];
26     head[u]=sn++;
27 }
28 void pdc(int u,int fa){
29     dfn[u]=low[u]=++dn;
30     for(int i=head[u],v;~i;i=S[i].ne){
31         v=S[i].v;
32         if(!dfn[v]){
33             sta[++tn]=Side(u,v);
34             pdc(v,u);
35             low[u]=min(low[u],low[v]);
36             if(low[v]>=dfn[u]){
37                 int su,sv;
38                 bsi[++bn]=0;
39                 while(tn){
40                     su=sta[tn].v;sv=sta[tn].ne;
41                     tn--;
42                     if(su==u&&sv==v) break;
43                     if(bin[su]!=bn){
44                         bin[su]=bn;
45                         bsi[bn]++;
46                     }
47                     if(bin[sv]!=bn){
48                         bin[sv]=bn;
49                         bsi[bn]++;
50                     }
51                 }
52             }
53         }else if(v!=fa){
54             low[u]=min(low[u],dfn[v]);
55             if(dfn[u]>dfn[v]) sta[++tn]=Side(u,v);
56         }
57     }
58 }
59 int main(){
60     cf2[0]=1;
61     for(int i=1;i<M;i++){
62         cf2[i]=cf2[i-1]<<1;
63         if(cf2[i]>=md) cf2[i]%=md; 
64     }
65     int t,m,u,v;
66     //scanf("%d",&t);
67     //while(t--){
68         scanf("%d%d",&n,&m);
69         init();
70         for(int i=0;i<m;i++){
71             scanf("%d%d",&u,&v);
72             add(u,v);
73             add(v,u);
74         }
75         ll ans=1;
76         for(int i=1;i<=n;i++) if(!dfn[i]) pdc(i,i);
77         for(int i=1;i<=bn;i++){
78             if(!bsi[i]) continue;
79             ans*=((cf2[bsi[i]]-1)%md+md)%md;
80             if(ans>=md) ans%=md;
81             m-=bsi[i];
82         }
83         ans*=cf2[m];
84         if(ans>=md) ans%=md;
85         printf("%lld
",ans);
86 //    }
87     return 0;
88 }
点双

其实直接dfs找环就行了。

 1 #include<cstdio>
 2 #include<stack>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int N=5e5+11,M=5e5+11;
 7 const ll md=998244353;
 8 struct Side{
 9     int v,ne;
10     Side(){}
11     Side(int v,int ne):v(v),ne(ne){}
12 }S[M<<1];
13 Side sta[M];
14 int n,m,sn,dn,bn,tn,head[N],vis[N],dep[N];
15 ll ans,cf2[M];
16 void init(){
17     sn=dn=bn=tn=0;
18     for(int i=0;i<=n;i++){
19         head[i]=-1;
20         vis[i]=0;
21     }
22 }
23 void add(int u,int v){
24     S[sn].v=v;
25     S[sn].ne=head[u];
26     head[u]=sn++;
27 }
28 void dfs(int u,int fa,int d){
29     dep[u]=d;
30     vis[u]=1;
31     for(int i=head[u],v;~i;i=S[i].ne){
32         v=S[i].v;
33         if(v==fa||vis[v]==2) continue;
34         if(vis[v]){
35             m-=d-dep[v]+1;
36             ans*=(cf2[d-dep[v]+1]-1+md)%md;
37             if(ans>=md) ans%=md; 
38         }else dfs(v,u,d+1);
39     }
40     vis[u]=2;
41 }
42 int main(){
43     cf2[0]=1;
44     for(int i=1;i<M;i++){
45         cf2[i]=cf2[i-1]<<1;
46         if(cf2[i]>=md) cf2[i]%=md; 
47     }
48     int t,u,v;
49     scanf("%d%d",&n,&m);
50     init();
51     for(int i=0;i<m;i++){
52         scanf("%d%d",&u,&v);
53         add(u,v);
54         add(v,u);
55     }
56     ans=1;
57     for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,i,0);
58     ans*=cf2[m];
59     if(ans>=md) ans%=md;
60     printf("%lld
",ans);
61     return 0;
62 }
dfs判环

1009 一道dp题,当时是+1做的,自己补了下。就每个技能最多有6种组合,dp[i][j]就是第i个技能,是用第j个组合按出来的,最少方案数。然后预处理一下,两两技能不同组合之间转移时需要多按的键数便可。

 1 #include<cstdio>
 2 #include<tr1/unordered_map>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const char jn[15][10][10]={
 7     {{"QQQ"},{"QQQ"},{"QQQ"},{"QQQ"},{"QQQ"},{"QQQ"}},
 8     {{"QQW"},{"WQQ"},{"QWQ"},{"QQW"},{"WQQ"},{"QWQ"}},
 9     {{"QQE"},{"EQQ"},{"QEQ"},{"QQE"},{"EQQ"},{"QEQ"}},
10     {{"WWW"},{"WWW"},{"WWW"},{"WWW"},{"WWW"},{"WWW"}},
11     {{"QWW"},{"WQW"},{"WWQ"},{"QWW"},{"WQW"},{"WWQ"}},
12     {{"WWE"},{"EWW"},{"WEW"},{"WWE"},{"EWW"},{"WEW"}},
13     {{"EEE"},{"EEE"},{"EEE"},{"EEE"},{"EEE"},{"EEE"}},
14     {{"QEE"},{"EQE"},{"EEQ"},{"QEE"},{"EQE"},{"EEQ"}},
15     {{"WEE"},{"EWE"},{"EEW"},{"WEE"},{"EWE"},{"EEW"}},
16     {{"QWE"},{"QEW"},{"WQE"},{"WEQ"},{"EWQ"},{"EQW"}},
17 };
18 const int N=1e5+11,inf=1e9+7;
19 int val[15][15][15][15],dp[N][15];
20 char s[N];
21 tr1::unordered_map<char,int> mmp;
22 void init(){
23     mmp['Y']=0;mmp['V']=1;mmp['G']=2;mmp['C']=3;mmp['X']=4;
24     mmp['Z']=5;mmp['T']=6;mmp['F']=7;mmp['D']=8;mmp['B']=9; 
25     for(int i=0;i<10;i++)
26         for(int j=0;j<10;j++)
27             for(int k=0;k<6;k++)
28                 for(int l=0;l<6;l++){
29                     for(int q=0,p;q<=3;q++){
30                         for(p=q;p<3;p++)
31                             if(jn[i][k][p]!=jn[j][l][p-q]) break;
32                         if(p>=3){
33                             val[i][j][k][l]=q;
34                             break;
35                         }
36                     }
37                 }
38 }
39 int main(){
40     init();
41     while(~scanf("%s",s)){
42         int lens=strlen(s);
43         for(int i=0;i<lens;i++)
44             for(int j=0;j<6;j++) dp[i][j]=inf;
45         for(int i=0;i<6;i++) dp[0][i]=4;
46         for(int i=1;i<lens;i++){
47             int j1=mmp[s[i-1]],j2=mmp[s[i]];
48             for(int k1=0;k1<6;k1++)
49                 for(int k2=0;k2<6;k2++)
50                     dp[i][k2]=min(dp[i][k2],dp[i-1][k1]+val[j1][j2][k1][k2]+1);
51         }
52         int ans=inf;
53         for(int i=0;i<6;i++) ans=min(ans,dp[lens-1][i]);
54         printf("%d
",ans);
55     }
56     return 0;
57 }
这就是我为什么不玩dota

1010 哎,字符串循环节水题,当时忘了,就没做这题。我们需要知道的任意长度后缀里的循环节长度是多少,那倒序求一遍kmp即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int N=1e7+11;
 7 const ll inf=1e18+7;
 8 char s1[N],s2[N];
 9 int ne[N];
10 void getne(char *s){
11     int i=0,j=-1,lens=strlen(s);
12     ne[0]=-1;
13     while(i<lens){
14         if(j==-1||s[i]==s[j]) ne[++i]=++j;
15         else j=ne[j]; 
16     }
17 }
18 int main(){
19     int a,b;
20     while(~scanf("%d%d%s",&a,&b,s1)){
21         int lens1=strlen(s1),lens2;
22         for(int i=0;i<lens1;i++){
23             if(s1[lens1-1-i]=='.'){
24                 s2[i]='';
25                 break;
26             }
27             s2[i]=s1[lens1-1-i];
28         }
29         getne(s2);
30         lens2=strlen(s2);
31         ll ans=-inf;
32         for(int i=1;i<=lens2;i++){
33             int len=i-ne[i]; 
34             ans=max(ans,1ll*a*i-1ll*b*len);
35         }
36         printf("%lld
",ans);
37     }
38     return 0;
39 }
我太菜了

1005 我第一道看的就是这题,当时就觉得是网络流能做,可惜当时做的人不多,就没开。干就完事了。然后因为任意两个机器人肯定不能走同样的路径,也就是每个位置的水平和垂直方向只能走一次,所以就是每个

位置抄成两个点,然后转向器无非就是在每个位置的水平和垂直的两点间连边,然后再把机器人与相应位置的水平方向连边,终点与相应位置的垂直方向连边,然后跑一遍,看最大流是不是等于机器人数就好了。

 1 #include<cstdio>
 2 #include<queue>
 3 using namespace std;
 4 const int N=2e4+11,inf=1e9+7;
 5 struct Side{
 6     int v,w,ne;
 7 }S[N<<2];
 8 char mp[111][111];
 9 int sb,se,sn,head[N],dep[N],cur[N];
10 void init(){
11     sn=0;
12     for(int i=sb;i<=se;i++) head[i]=-1;
13 }
14 void add(int u,int v,int w){
15     S[sn].v=v;
16     S[sn].w=w;
17     S[sn].ne=head[u];
18     head[u]=sn++;
19 }
20 void addE(int u,int v,int w,int op){
21     add(u,v,w);
22     add(v,u,op ? 0 : w );
23 }
24 bool bfs(){
25     for(int i=sb;i<=se;i++) dep[i]=0;
26     queue<int> q;
27     dep[sb]=1;
28     q.push(sb);
29     int u,v;
30     while(!q.empty()){
31         u=q.front();
32         q.pop();
33         for(int i=head[u];~i;i=S[i].ne){
34             v=S[i].v;
35             if(S[i].w>0&&!dep[v]){
36                 dep[v]=dep[u]+1;
37                 if(v==se) return true;
38                 q.push(v);
39             }
40         }
41     }
42     return false;
43 }
44 int dfs(int u,int minf){
45     if(!minf||u==se) return minf;
46     int v,flow;
47     for(int &i=cur[u];~i;i=S[i].ne){
48         v=S[i].v;
49         if(S[i].w>0&&dep[v]==dep[u]+1){
50             flow=dfs(v,min(minf,S[i].w));
51             if(flow){
52                 S[i].w-=flow;
53                 S[i^1].w+=flow;
54                 return flow;
55             }
56         }
57     }
58     return 0;
59 }
60 int dinic(){
61     int maxf=0,flow;
62     while(bfs()){
63         for(int i=sb;i<=se;i++) cur[i]=head[i];
64         while(flow=dfs(sb,inf)) maxf+=flow;
65     }
66     return maxf;
67 }
68 int main(){
69     int t,n,m,a,b,x;
70     scanf("%d",&t);
71     while(t--){
72         scanf("%d%d%d%d",&n,&m,&a,&b);
73         sb=0;se=2*n*m+1;
74         init();
75         for(int i=0;i<n;i++){
76             scanf("%s",mp[i]);
77             for(int j=0;j<m;j++){
78                 //printf("%d %d
",i*m+j+1,n*m+i*m+j+1);
79                 if(mp[i][j]=='1') continue;
80                 addE(i*m+j+1,n*m+i*m+j+1,1,0);
81                 if(i&&mp[i-1][j]!='1') addE(i*m+j+1,(i-1)*m+j+1,1,0);
82                 if(j&&mp[i][j-1]!='1') addE(n*m+i*m+j+1,n*m+i*m+j,1,0);
83             }
84         }
85         for(int i=1;i<=a;i++){
86             scanf("%d",&x);
87             if(mp[0][x-1]!='1') addE(sb,x,1,1);
88         }
89         for(int i=1;i<=b;i++){
90             scanf("%d",&x);
91             if(mp[n-1][x-1]!='1') addE((n-1)*m+x,se,1,1);
92         }
93         if(dinic()!=a) printf("No
");
94         else printf("Yes
");
95     }
96     return 0; 
97 }
一血的诱惑

1001 当时鲲鲲已经做出来了,可惜卡常数,最后重现才补出来。https://blog.csdn.net/mmk27_word/article/details/101638730

1011 +1最后思路已经来了,跟题解类似,可惜没敲完。(大小姐是不写博客的)

能出的题还是挺多的,下次把所有可惜没做到的,转换成做到的。

原文地址:https://www.cnblogs.com/LMCC1108/p/11577614.html