zoukankan      html  css  js  c++  java
  • [考试反思]0410省选模拟67:迷惑

    现在想想,先做$T3$真乃人间迷惑行为。

    部分分不多的一场考试,$T1$部分分最多结果没花时间光荣爆零,结果正解真的就是一个暴力+大力分类讨论

    $T2$也比较可想,然而看着$75pts$的子任务心中有几分慌张,苟了个暴力跑路了。

    结果一个弱智$T3$的$10pts$部分分$O(n^8)$暴写了$2.8k$。从这代码长度看是不是$10pts$您施舍的有点少啊。

    其余部分分一点用没有,不知道咋想的。

    T1:链

    大意:维护操作:加边,询问有几个点满足:删掉之后图中剩下的都是若干链。$n,m le 200000,$

    那就分类讨论就完了呗。

    链就是,所有点度数$le 2$,且没有简单环。

    如果不出现度数$>2$的点:

    若有超过一个环,答案$0$

    若有恰好一个环,答案是环大小

    如果没有环,答案是点数

    如果出现了度数$> 2$的点,那么当度数$=3$的点第一次出现时,答案只可能是这个点以及与其相连的三个点。

    对这四个点分别维护删掉其中一个点之后的四个图,如果依旧有度数$ge 3$的点或者是出环了这个点就不可行。

    维护$5$个度数数组,$5$个并查集,其中一个要维护大小。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 200005
     4 vector<int>v[S];
     5 int ok[5],n,m,ans,T,f[5][S],sz[S],deg3,q[5],deg[5][S],cir; char s[9];
     6 int find(int k,int p){return f[k][p]==p?p:f[k][p]=find(k,f[k][p]);}
     7 int main(){
     8     cin>>n>>m; ans=n;
     9     for(int i=1;i<=n;++i)sz[i]=1;
    10     for(int j=0;j<5;++j)for(int i=1;i<=n;++i)f[j][i]=i;
    11     for(int i=1,a,b;i<=m;++i){
    12         scanf("%s",s);
    13         if(s[0]=='Q')printf("%d
    ",ans);
    14         else{
    15             scanf("%d%d",&a,&b);
    16             if(!ans)continue;
    17             v[a].push_back(b);v[b].push_back(a);
    18             deg[0][a]++;deg[0][b]++;
    19             if(deg[0][a]<deg[0][b])swap(a,b);
    20             if(deg3){
    21                 for(int z=1;z<=4;++z)if(ok[z]){
    22                     if(a==q[z]||b==q[z])continue;
    23                     ans--;
    24                     deg[z][a]++; deg[z][b]++;
    25                     if(deg[z][a]>2||deg[z][b]>2)ok[z]=0;
    26                     int x=find(z,a),u=find(z,b);
    27                     if(x==u)ok[z]=0;
    28                     else f[z][x]=u;
    29                     ans+=ok[z];
    30                 }
    31             }else if(deg[0][a]==3){
    32                 q[1]=a;q[2]=v[a][0];q[3]=v[a][1];q[4]=v[a][2]; deg3=1; ans=0;
    33                 for(int z=1;z<=4;++z){
    34                     ok[z]=1;
    35                     for(int i=1;i<=n;++i)if(i!=q[z])for(int j=0;j<v[i].size();++j)if(i<v[i][j]&&v[i][j]!=q[z]){
    36                         deg[z][i]++; deg[z][v[i][j]]++;
    37                         if(deg[z][i]>2)ok[z]=0;
    38                         if(deg[z][v[i][j]]>2)ok[z]=0;
    39                         int u=find(z,i),x=find(z,v[i][j]);
    40                         if(u==x)ok[z]=0;
    41                         else f[z][u]=x;
    42                     }ans+=ok[z];
    43                 }
    44             }else{
    45                 a=find(0,a);b=find(0,b);
    46                 if(a==b&&!cir)cir=1,ans=sz[a];
    47                 else if(a==b)ans=0;
    48                 else sz[a]+=sz[b],f[0][b]=a;
    49             }
    50         }
    51     }
    52 }
    View Code

    T2:子集和

    大意:给出背包数组(最多$10000$个位置有值),还原字典序最小的物品序列。$|S| le 60,T le 100,w_i le 10^{10}$

    首先对于$a_i ge 0$的点,直接取出当前能被表示出来的最小数,做逆背包就行。

    然后对于负数,首先,我们可以发现,整个数列的最大值减去次大值得到的,就是当前剩下的所有数中,绝对值最小者的绝对值。

    于是做一遍逆背包把它搞掉。所以我们能用同样的方法得到所有数的绝对值,问题在于定号。

    粘一段我给别人讲过的:

    考虑这么来理解,这题是一个背包的过程。

    01背包的实质,加入一个体积为v的物品时(先考虑正的),类似于将现有的dp数组向右平移v位之后,加到原数组上。

    那么考虑v是负的的时候会发生什么,其实只是变成了向左平移。

    对于最开始00001020000这个数组,加入一个体积为3的物品,就是先平移成00000001020再叠加得到00001021020.

    如果加入一个体积为-3的物品那就是先平移成01020000000再叠加得到01021020000。

    我们发现两次加入物品得到的dp数组的值是完全一样的,只不过下标完全错开了v位而已。

    所以说,不论取正负,得到的最后的dp数组都是一个样子的,只不过下标不同。

    所以当我们确定最大值之后,整个数组就定位了,那么整个数组就一定与题目读入的相符.

    为了让字典序最小,我们优先让绝对值大的数负过去。于是我们逐位确定。

    做一遍背包,对于尚未确定的值就把正的负的都丢进去,最后看看最大值是否能被表示出来即可。时间复杂度$O(10000T|S|)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 map<long long,int>num,M;
     4 long long s[11111],cnt[11111],mx,ans[11111];bool dp[11111];
     5 int main(){
     6     for(int i=0;i<61;++i)num[1ll<<i]=i;
     7     int t;cin>>t;for(int T=1;T<=t;++T){ printf("Case #%d: ",T);
     8         int _;long long tot=0; cin>>_;
     9         for(int i=1;i<=_;++i)scanf("%lld",&s[i]),M[s[i]]=i; mx=s[_];
    10         for(int i=1;i<=_;++i)scanf("%lld",&cnt[i]),tot+=cnt[i];
    11         int n=num[tot],pt2=1,pt1=1;
    12         for(int r=1;r<=n;++r){
    13             if(cnt[1]>=2){
    14                 ans[r]=0;
    15                 for(int i=1;i<=_;++i)cnt[i]/=2;
    16             }else{
    17                 while(!cnt[pt1])pt1++; pt2=pt1+1;
    18                 while(!cnt[pt2])pt2++;
    19                 int x=s[pt2]-s[pt1]; ans[r]=x;
    20                 for(int j=1;j<=_;++j)cnt[M[s[j]+x]]-=cnt[j];
    21             }
    22         }
    23         sort(ans+1,ans+1+n);
    24         for(int i=n;i;--i)if(ans[i]){
    25             ans[i]=-ans[i];
    26             for(int j=1;j<=_;++j)dp[j]=0;
    27             dp[M[0]]=1;
    28             for(int j=i;j<=n;++j)if(ans[j]>0){for(int k=_;k;--k)if(dp[k])dp[M[s[k]+ans[j]]]|=dp[k];}
    29                 else for(int k=1;k<=_;++k)if(dp[k])dp[M[s[k]+ans[j]]]|=dp[k];
    30             for(int j=i-1;ans[j];--j){
    31                 for(int k=_;k;--k)if(dp[k])dp[M[s[k]+ans[j]]]|=dp[k];
    32                 for(int k=1;k<=_;++k)if(dp[k])dp[M[s[k]-ans[j]]]|=dp[k];
    33             }if(!dp[_])ans[i]=-ans[i];
    34         }sort(ans+1,ans+1+n);
    35         for(int i=1;i<=n;++i)printf("%lld ",ans[i]);
    36         M.clear();puts("");
    37     }
    38 }
    View Code

    T3:写作

    大意:你有若干互不相同的名词,及物动词,不及物动词,形容词。支持以下句法的情况下你能写多少种文章$F$。$n,adj,vt,vi le 200$

    题解怎么又锅了?

    $N=S,N=adj+N,N=n+n+...+n,S=vi,S=N+vt,S=N+vi,S=N+vt+N,P=S,S'=S(S eq vi),P=S'+S'+...+S',s=P+P+...+P,F=s+s+...+s$

    首先你可以简单的记忆化搜索一下。暴写好久就可以得到$10pts$的好成绩。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define mod 1000000007
     4 //N= (n+n+...+n) or (s) or (adj+N)
     5 //s= (N+vt+N) or (vt+N) or (N+vi) or (vi)
     6 //A=(s' +s' +...+s') B=(A+A+...+A) F=(B+B+...+B)
     7 //How many kinds of C using all of vt,vi,n,adj exactly once?
     8 struct hash_map{
     9     #define R 3860187
    10     int fir[R],l[R],to[R],v[R],ec;
    11     int&operator[](int x){int r=x%R;
    12         for(int i=fir[r];i;i=l[i])if(to[i]==x)return v[i];
    13         l[++ec]=fir[r];fir[r]=ec;to[ec]=x;return v[ec]=-1;
    14     }
    15 }_F,_A,_B,_S,_N;
    16 int&ggt(hash_map&x,int a,int b,int c,int d){return x[a<<24|b<<16|c<<8|d];}
    17 int C[222][222],fac[222];
    18 int mo(int a){return a>=mod?a-mod:a;}
    19 int S(int vt,int vi,int n,int adj);
    20 int N(int vt,int vi,int n,int adj){
    21     int&ans=ggt(_N,vt,vi,n,adj);
    22     if(ans!=-1)return ans;
    23     ans=(S(vt,vi,n,adj)+(adj?1ll*adj*N(vt,vi,n,adj-1):0))%mod;
    24     if(!vt&&!vi&&!adj)ans=mo(ans+fac[n]);
    25     return ans;
    26 }
    27 int S(int vt,int vi,int n,int adj){
    28     int&ans=ggt(_S,vt,vi,n,adj);
    29     if(ans!=-1)return ans;
    30     if(vi==1&&vt==0&&n==0&&adj==0)return ans=1;ans=0;
    31     if(vt)for(int VT=0;VT<vt;++VT)for(int VI=0;VI<=vi;++VI)for(int __N=0;__N<=n;++__N)for(int ADJ=0;ADJ<=adj;++ADJ)
    32         ans=(ans+1ll*N(VT,VI,__N,ADJ)*N(vt-VT-1,vi-VI,n-__N,adj-ADJ)%mod*C[vt-1][VT]%mod*C[vi][VI]%mod*C[n][__N]%mod*C[adj][ADJ]%mod*vt)%mod;
    33     //cerr<<vt<<' '<<vi<<' '<<n<<' '<<adj<<' '<<ans<<endl;
    34     if(vt)ans=(ans+N(vt-1,vi,n,adj)*1ll*vt)%mod;
    35     if(vi)ans=(ans+N(vt,vi-1,n,adj)*1ll*vi)%mod;
    36     return ans;
    37 }
    38 int A(int vt,int vi,int n,int adj){
    39     if(!vt&&!vi&&!n&&!adj)return 1;
    40     int&ans=ggt(_A,vt,vi,n,adj);
    41     if(ans!=-1)return ans;ans=0;
    42     for(int VT=0;VT<=vt;++VT)for(int VI=0;VI<=vi;++VI)for(int N=0;N<=n;++N)for(int ADJ=0;ADJ<=adj;++ADJ)if(VT+VI+N+ADJ)
    43         ans=(ans+1ll*(S(VT,VI,N,ADJ)-(!VT&&!N&&!ADJ&&VI==1))*A(vt-VT,vi-VI,n-N,adj-ADJ)%mod*C[vt][VT]%mod*C[vi][VI]%mod*C[n][N]%mod*C[adj][ADJ])%mod;
    44     return ans;
    45 }
    46 int B(int vt,int vi,int n,int adj){
    47     if(!vt&&!vi&&!n&&!adj)return 1;
    48     int&ans=ggt(_B,vt,vi,n,adj);
    49     if(ans!=-1)return ans;ans=0;
    50     for(int VT=0;VT<=vt;++VT)for(int VI=0;VI<=vi;++VI)for(int N=0;N<=n;++N)for(int ADJ=0;ADJ<=adj;++ADJ)if(VT+VI+N+ADJ)
    51         ans=(ans+1ll*A(VT,VI,N,ADJ)*B(vt-VT,vi-VI,n-N,adj-ADJ)%mod*C[vt][VT]%mod*C[vi][VI]%mod*C[n][N]%mod*C[adj][ADJ])%mod;
    52     return ans;
    53 }
    54 int F(int vt,int vi,int n,int adj){
    55     if(!vt&&!vi&&!n&&!adj)return 1;
    56     int&ans=ggt(_F,vt,vi,n,adj);
    57     if(ans!=-1)return ans;ans=0;
    58     for(int VT=0;VT<=vt;++VT)for(int VI=0;VI<=vi;++VI)for(int N=0;N<=n;++N)for(int ADJ=0;ADJ<=adj;++ADJ)if(VT+VI+N+ADJ)
    59         ans=(ans+1ll*B(VT,VI,N,ADJ)*F(vt-VT,vi-VI,n-N,adj-ADJ)%mod*C[vt][VT]%mod*C[vi][VI]%mod*C[n][N]%mod*C[adj][ADJ])%mod;
    60     return ans;
    61 }
    62 int main(){
    63     int vt,vi,n,adj;cin>>vt>>vi>>n>>adj;
    64     for(int i=0;i<=200;++i)for(int j=C[i][0]=1;j<=i;++j)C[i][j]=mo(C[i-1][j-1]+C[i-1][j]);
    65     for(int i=fac[0]=1;i<=200;++i)fac[i]=fac[i-1]*1ll*i%mod; fac[0]=0;
    66     cout<<F(vt,vi,n,adj)<<endl;
    67 }
    这份代码必须纪念

    抽象一下问题,我们把一个名词短语$N$(包括i句子$S$)当成树的一个节点。

    先不考虑形容词,以及段落$P$与章节$s$,暂且只考虑那种一个文章只有一节一段若干句子的情况。

    那么,$N+vt+N$所形成的就是一个有两个儿子的节点。$vt+N$和$N+vi$都是有一个儿子的。$vi$或$n+n+...+n$都可以作为叶节点。

    为了简便,称二号点代表有$2$个儿子的点。其余同理。

    设一个$A[i]$表示用$i$个带标号二号点构成一棵叶节点空缺的树的方案数,$A[i]=inom{2i}{i+1} (i-1)!$

    设一个$dp[i][j]$表示在有且仅有叶子空缺的情况下,用$i$个带标号的二号点构成$j$棵树的方案数(树与树之间也有序)。直接用$A$转移即可。

    这里题解的式子挂掉了,要注意因为是有标号的,所以转移的时候要带一个组合数。

    枚举最后一棵树的大小。这里复杂度是$O(n^3)$的。(同级不纠结)

    然后考虑一号点,它有零或一个父亲有一个儿子,所以它的作用就是插在任意一条边的中间。

    设$g[i][j][k]$表示$i$个二号点$j$个一号点$k$个树的方案数,那么分类讨论这个一号点是新单独生成了一棵树,还是插在了原来的边上(包括树根的上方)

    $g[i][j][k]=g[i][j-1][k-1] imes k + g[i][j-1][k] imes (2i+j-1+k)$。题解又锅了,前面因为要考虑树的顺序所以应该乘$k$

    这里复杂度也是$O(n^3)$的

    最后只需要枚举二号点,一号点,树的数量,即可推得零号点的数量,叶子节点的数量,进而可以知道$n+n+...+n$的名词短语数量。

    含义上这需要一个斯特林数,但是不是很对,因为词语之前前后顺序也有关,所以其实是全排列再插板,阶乘乘组合数。

    然后再把所有叶子节点做一个选排列(斯特林集合之间有序)。把$vt,vi$分配给各号点是两个组合数。

    再考虑形容词的贡献,它是用来修饰名词短语的,所以其实和一号点是类似的,插在边之间就好了,只不过不能插在根的上方。也是个上升幂。

    还要考虑的就是段,章节之类的问题。我们发现两个句子之间的间隙只可能是:句尾/段尾/节尾。而且没有限制,所以撑一个$3$的幂就行了。

    有一点细节。要注意每个数组的上界是多少。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define mod 1000000007
     4 int mo(int a){return a>=mod?a-mod:a;}
     5 int C[666][666],A[666],f[233][233],g[201][401][401],S[233][666],fac[401],ans,pw[401],ex[601];
     6 int main(){
     7     f[0][0]=S[0][0]=1;
     8     for(int i=fac[0]=pw[0]=1;i<=400;++i)fac[i]=fac[i-1]*1ll*i%mod,pw[i]=pw[i-1]*3ll%mod;
     9     for(int i=0;i<=600;++i)for(int j=C[i][0]=1;j<=i;++j)C[i][j]=mo(C[i-1][j-1]+C[i-1][j]);
    10     for(int i=0;i<=200;++i)for(int j=1;j<=i;++j)S[i][j]=fac[i]*1ll*C[i-1][j-1]%mod;
    11     for(int i=0;i<=600;++i)A[i]=ex[i]=1;
    12     for(int i=1;i<=200;++i)for(int j=i<<1;j>i+1;--j)A[i]=A[i]*1ll*j%mod;
    13     for(int i=1;i<=200;++i)for(int j=i;j<=200;++j)for(int k=1;k<=j;++k)f[i][j]=(f[i][j]+1ll*f[i-1][j-k]*A[k]%mod*C[j][k])%mod;
    14     for(int i=0;i<=200;++i){
    15         for(int j=0;j<=i;++j)g[i][0][j]=f[j][i];
    16         for(int j=1;j+i<=400;++j)for(int k=1;k<=i+j;++k)g[i][j][k]=(g[i][j-1][k-1]*1ll*k+g[i][j-1][k]*(2ll*i+j+k-1))%mod;
    17     }
    18     int vt,vi,n,adj; cin>>vt>>vi>>n>>adj;
    19     for(int i=0;i<=600;++i)for(int j=i+adj-1;j>=i;--j)ex[i]=ex[i]*1ll*j%mod;
    20     for(int c2=0;c2<=vt;++c2)for(int c1=vt-c2;c1+c2<=vt+vi;++c1)for(int ts=1;ts<=vt+vi;++ts){
    21         int c0=vt+vi-c2-c1,lf=ts+c2;
    22         ans=(ans+1ll*C[vt][c2]*C[vi][c0]%mod*S[n][lf-c0]%mod*g[c2][c1][ts]%mod*C[lf][c0]%mod*fac[c0]%mod*pw[ts-1]%mod*ex[c1+c2*2])%mod;
    23     }cout<<ans<<endl;
    24 }
    View Code
  • 相关阅读:
    Spring中常见的设计模式——工厂模式
    Java编程思想——第14章 类型信息(二)反射
    Java编程思想——第17章 容器深入研究(二)
    Java编程思想——第17章 容器深入研究(一)
    python笔记-正则表达式常用函数
    python笔记-文件读写
    AWK编程
    ORA-01555错误
    group_concat的使用
    expect-调试模式的使用
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12677560.html
Copyright © 2011-2022 走看看