zoukankan      html  css  js  c++  java
  • [考试反思]1019csp-s模拟测试80(a):天遣

    A组题,所以把榜粘全了。

    第6名,被卡在刚好正中间。

    我最近干什么伤天害理的事了?(例如说没有在skyh去上厕所的时候捶他)

    上来看T1,非常贴心出题人直接把递推式子给你了,然后就和斐波数的递推一样了。

    套一个矩乘和CRT就完事。我很懵啊但是打完了调一调就过样例了。

    然后保存。刚想交,这时候就死机了。

    彻底死机了,啥都动不了。我也没暴力打表也没踹主机怎么就突然死机了???

    然后就没有然后了。心态稍炸。无奈重启。

    冷静了挺长一段时间后,虽说心情还是很烦躁,但是还是再码了一遍,打暴力,挂对拍。

    稳住100分之后,心情还是很乱(可能也有要放假了的因素),T3送上一个网络流暴力

    然后剪枝,细节打错了,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
    ",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
    ",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
    ",tot);
    47     for(int i=1;i<=t;++i)if(!ans[i])printf("%d ",i);puts("");
    48 }
    View Code

    思路积累:

    • 考虑退流的实际意义
  • 相关阅读:

    es -Aggregations
    散列表学习
    SpringCloud (一)——基本的搭建
    1.5 中不支持 lambda 表达 java
    区块链 (一)——基础
    线性表
    Redis(四)——消息队列
    rune is alias of int32
    wall time
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11708155.html
Copyright © 2011-2022 走看看