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
  • 相关阅读:
    AX 2012 Security Framework
    The new concept 'Model' in AX 2012
    How to debug the SSRS report in AX 2012
    Using The 'Report Data Provider' As The Data Source For AX 2012 SSRS Report
    Deploy SSRS Report In AX 2012
    AX 2012 SSRS Report Data Source Type
    《Taurus Database: How to be Fast, Available, and Frugal in the Cloud》阅读笔记
    图分析理论 大纲小结
    一文快速了解Posix IO 缓冲
    #转载备忘# Linux程序调试工具
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12677560.html
Copyright © 2011-2022 走看看