[考試反思]1019csp-s模擬測試80(a):天遣

A組題,因此把榜粘全了。ios

第6名,被卡在恰好正中間。c++

 

我最近幹什麼傷天害理的事了?(例如說沒有在skyh去上廁所的時候捶他)算法

上來看T1,很是貼心出題人直接把遞推式子給你了,而後就和斐波數的遞推同樣了。數組

套一個矩乘和CRT就完事。我很懵啊可是打完了調一調就過樣例了。網絡

而後保存。剛想交,這時候就死機了。ide

完全死機了,啥都動不了。我也沒暴力打表也沒踹主機怎麼就忽然死機了???ui

而後就沒有而後了。心態稍炸。無奈重啓。spa

冷靜了挺長一段時間後,雖然說心情仍是很煩躁,可是仍是再碼了一遍,打暴力,掛對拍。code

穩住100分以後,心情仍是很亂(可能也有要放假了的因素),T3送上一個網絡流暴力blog

而後剪枝,細節打錯了,50->10。後來也沒上對拍。

沒怎麼看時間,可是好像還剩一點。T2一看到複雜度是$O(n^3)$或$O(n^4)$之類的感受會很麻煩很難想。

而後就沒有想出來那個最簡單最傻逼的暴力。

其實全程都沒有靜下心來作題。並且對A組題貌似仍是有點恐懼。

可是此次的A組題真的沒有那麼難。三道題其實均可作(畢竟都有A的,呃,算上yxm數組開小的T3的話)

不要高估題目難度。不要怕題目,怕就必定輸了。

要穩下心來作題,儘可能避免外界因素的干擾。

要冷靜應對一切可能發生的突發狀況。

儘可能及時地交代碼,儘可能頻繁地存代碼。

要攢RP防止天遣。。。

 

T1:貝爾數

能夠發現第二個式子和斐波數的遞推相似。而數據範圍須要log掉那個n。

轉移週期是質數大小的級別,而模數恰好是5個不大於50的數的乘積。

而後矩陣快速冪便可。只不過最後一項的轉移稍微複雜了一點要特殊處理一下。

現場YY出CRT已是常態了。

 1 #include<cstdio>
 2 #define Mod 95041567
 3 const int mod[6]={0,31,37,41,43,47};
 4 int Ans[6],base[55][55],ans[55],n,t,C[6][55][55],b[6][55],res[55][55];
 5 void ex_gcd(int a,int b,int &x,int &y){
 6     if(!b){x=1;y=0;return;}
 7     ex_gcd(b,a%b,x,y);
 8     int r=x;x=y;y=r-a/b*y;
 9 }
10 int CRT(){int Cans=0,x,y;
11     for(int p=1;p<=5;++p){
12         ex_gcd(Mod/mod[p],mod[p],x,y);x=x%Mod+Mod;
13         Cans=(Cans+1ll*x*Ans[p]%Mod*(Mod/mod[p]))%Mod;
14     }
15     return Cans;
16 }
17 void mult_base(int mo){
18     for(int i=1;i<=mo;++i)for(int j=1;j<=mo;++j)for(int k=1;k<=mo;++k)res[i][j]+=base[i][k]*base[k][j];
19     for(int i=1;i<=mo;++i)for(int j=1;j<=mo;++j)base[i][j]=res[i][j]%mo,res[i][j]=0;
20 }
21 void mult_ans(int mo){
22     for(int i=1;i<=mo;++i)for(int j=1;j<=mo;++j)res[0][j]+=ans[i]*base[i][j];
23     for(int i=1;i<=mo;++i)ans[i]=res[0][i]%mo,res[0][i]=0;
24 }
25 int main(){//freopen("t1.in","r",stdin);freopen("t1.out","w",stdout);
26     #define mo mod[p]
27     for(int p=1;p<=5;++p){
28         for(int i=0;i<=50;++i)C[p][i][0]=1;
29         for(int i=1;i<=50;++i)for(int j=1;j<=i;++j)C[p][i][j]=(C[p][i-1][j-1]+C[p][i-1][j])%mo;
30         b[p][0]=1;
31         for(int i=1;i<=50;++i)for(int j=0;j<i;++j)b[p][i]=(b[p][i]+b[p][j]*C[p][i-1][j])%mo;
32     }scanf("%d",&t);
33     while(t--){scanf("%d",&n);
34         for(int p=1;p<=5;++p){
35             for(int i=1;i<=mo;++i)ans[i]=b[p][i];
36             for(int i=1;i<=mo;++i)for(int j=1;j<=mo;++j)base[i][j]=0;
37             for(int i=1;i<=mo;++i)base[i][i]=base[i][i-1]=1;
38             base[1][mo]=base[2][mo]=1;
39             int t=(n-1)/mo;
40             for(;t;t>>=1,mult_base(mo))if(t&1)mult_ans(mo);
41             Ans[p]=ans[(n-1)%mo+1];
42         }
43         printf("%d\n",CRT());
44     }
45 }
View Code

 

T2:穿越廣場

dp[i][j][k][l]表示已經走了i步,有j個‘D’,和第一個串匹配到k長度,和第二個串匹配到l長度。

KMP一下找到若是匹配失敗的話會怎麼轉移。而後50分的暴力就出來了。

%%%猿小鯤打了5.2k得了10分。

然而其實兩個串分別匹配是沒有意義的,和AC自動機專題的DP就很像了。

dp[i][j][k][l]表示i已經走了i步而且用了j個‘D’,目前匹配到AC自動機上的第k個節點,目前和兩個串是否已經匹配完成過(0/1/2/3二進制壓狀態)

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 #define mst(p) memset(p,0,sizeof p)
 5 int mod(int p){return p>=1000000007?p-1000000007:p;}
 6 int trie[255][2],rt,cnt,q[255],fail[255],suc[255],dp[205][105][205][4],ans;char s[205];
 7 void build(int &p,int al,int ord){
 8     if(!p)p=++cnt;
 9     if(!s[al]){suc[p]|=ord;return;}
10     build(trie[p][s[al]=='D'],al+1,ord);
11 }
12 void bfs(){
13     q[1]=1;trie[0][0]=trie[0][1]=rt;
14     for(int qh=1,qt=1;qh<=qt;++qh)for(int i=0;i<=1;++i)
15         if(trie[q[qh]][i])fail[q[++qt]=trie[q[qh]][i]]=trie[fail[q[qh]]][i];
16         else trie[q[qh]][i]=trie[fail[q[qh]]][i];
17 }
18 int main(){
19     int t;scanf("%d",&t);
20     while(t--){
21         int n,m;scanf("%d%d%s",&m,&n,s);build(rt,0,1);scanf("%s",s);build(rt,0,2);
22         bfs();
23         for(int i=1;i<=cnt;++i)for(int j=i;j;j=fail[j])suc[i]|=suc[j];
24         dp[0][0][rt][0]=1;
25         for(int i=0;i<n+m;++i)for(int j=0;j<=n;++j)for(int k=1;k<=cnt;++k)for(int l=0;l<=3;++l){
26             dp[i+1][j+1][trie[k][1]][l|suc[trie[k][1]]]=mod(dp[i+1][j+1][trie[k][1]][l|suc[trie[k][1]]]+dp[i][j][k][l]);
27             dp[i+1][j][trie[k][0]][l|suc[trie[k][0]]]=mod(dp[i+1][j][trie[k][0]][l|suc[trie[k][0]]]+dp[i][j][k][l]);
28         }
29         for(int k=1;k<=cnt;++k)ans=mod(ans+dp[n+m][n][k][3]);printf("%d\n",ans);
30         rt=cnt=ans=0;mst(dp);mst(fail);mst(suc);mst(trie);
31     }
32 }
View Code

 

T3:舞動的夜晚

這可能纔是真正的A組難度吧。。。我感受前兩題好像的確是聯賽知識點聯賽難度。。。

暴力強制某個邊必選,跑t次二分圖匹配看可否達到最大流便可,能拿到50分。

而我不會匈牙利算法,我仍是打的網絡流來作二分圖匹配。

那麼繼續想,網絡流的特色在於能夠退流。

那麼在最大流的圖上,經過退流,能夠獲得其它任意一種合法的最大匹配方案。

已經被用掉流量的邊固然是合法的。

而後咱們把圖裏的全部用到的邊反向,這就至關於退流了。

退流以後若是能再次流滿,那麼新的決策上的邊就和你建的反向邊成環了。

因此在新的圖上tarjan找強聯通份量。若是一條邊的兩個端點在同一個強聯通份量裏,那麼它就存在於某一種退流方式裏。

因此不合法的邊就是不存在於最開始的最大流裏,而在tarjan中兩端點也不屬於同一個scc。

%%%yxs考場上就會作。

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int n,m,t,ans[100005],x[100005],y[100005],fir[20005],l[240005],to[240005],w[240005],cnt=1;
 5 int q[20005],dep[20005],bel[20005],dfn[20005],low[20005],tim,sta[20005],top,ins[20005],scc;
 6 int match[20005],tot;
 7 void link(int a,int b,int v=0){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;w[cnt]=v;}
 8 bool bfs(){
 9     dep[0]=1;for(int i=1;i<=n+m+1;++i)dep[i]=0;
10     for(int qh=1,qt=1;qh<=qt;++qh)for(int i=fir[q[qh]];i;i=l[i])if(w[i]&&!dep[to[i]])dep[to[i]]=dep[q[qh]]+1,q[++qt]=to[i];
11     return dep[n+m+1]>0;
12 }
13 int dfs(int p,int flow){int res=flow;
14     if(p==n+m+1)return flow;
15     for(int i=fir[p];i;i=l[i])if(dep[to[i]]==dep[p]+1&&flow&&w[i]){
16         int r=dfs(to[i],1);
17         if(!r)dep[to[i]]=0;
18         flow-=r;w[i]-=r;w[i^1]+=r;
19     }return res-flow;
20 }
21 void tarjan(int p,int fa){
22     sta[++top]=p;dfn[p]=low[p]=++tim;ins[p]=1;
23     for(int i=fir[p];i;i=l[i])if(!dfn[to[i]])tarjan(to[i],p),low[p]=min(low[p],low[to[i]]);
24         else if(ins[to[i]])low[p]=min(low[p],dfn[to[i]]);
25     if(dfn[p]==low[p]){
26         scc++;
27         do{bel[sta[top]]=scc;ins[sta[top--]]=0;}while(sta[top+1]!=p);
28     }
29 }
30 int main(){
31     scanf("%d%d%d",&n,&m,&t);
32     for(int i=1;i<=t;++i)scanf("%d%d",&x[i],&y[i]),link(x[i],y[i]+n,1),link(y[i]+n,x[i],0);
33     for(int i=1;i<=n;++i)link(0,i,1),link(i,0,0);
34     for(int i=1;i<=m;++i)link(i+n,n+m+1,1),link(n+m+1,i+n,0);
35     int max_flow=0;
36     while(bfs())max_flow+=dfs(0,55555);
37     for(int i=1;i<=t;++i)if(!w[i<<1])ans[i]=1;
38     for(int i=1;i<=n;++i)if(!w[t+i<<1])match[i]=1;
39     for(int i=1;i<=m;++i)if(!w[t+n+i<<1])match[n+i]=1;
40     for(int i=0;i<=n+m+1;++i)fir[i]=0;cnt=0;
41     for(int i=1;i<=t;++i)if(ans[i])link(y[i]+n,x[i]);else link(x[i],y[i]+n);
42     for(int i=1;i<=n;++i)if(match[i])link(i,0);else link(0,i);
43     for(int i=1;i<=m;++i)if(match[i+n])link(n+m+1,i+n);else link(n+i,n+m+1);
44     for(int i=0;i<=n+m+1;++i)if(!dfn[i])tarjan(i,0);
45     for(int i=1;i<=t;++i)if(bel[x[i]]==bel[y[i]+n])ans[i]=1;
46     for(int i=1;i<=t;++i)tot+=ans[i]^1;printf("%d\n",tot);
47     for(int i=1;i<=t;++i)if(!ans[i])printf("%d ",i);puts("");
48 }
View Code

思路積累:

  • 考慮退流的實際意義
相關文章
相關標籤/搜索