[考试反思]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\n",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 }

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 }

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 \neq 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]=\binom{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] \times k + g[i][j-1][k] \times (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 }

原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12677560.html

时间: 2024-10-12 07:25:41

[考试反思]0410省选模拟67:迷惑的相关文章

[考试反思]0114省选模拟7:迷离

这次考得相对不错,但是没什么水准. 只不过记得T1这道原题而已.虽说我忘了怎么做,而且数据范围不一样...差不多是从头想的. 但是并没有AC,像个弱智一样,有两个细节写的完全不对还有80分运气也是真好. 其实挂了不止两个细节...以为是原题于是上来就写20分钟写完,然后过一会出一个锅... 然后看T2,感觉$O(nk^2)$也许差不多?常数很大...但也不会别的.挺好想但是不是很好写. 于是乎强烈谴责cbx没素质暴力水题考后还不改正解的无脸行径 于是就开始写,写了一个半小时. 看T3,绝对大神题

[考试反思]0113省选模拟6:过载

真累啊...离上次放假也挺久,离下次放假也挺久,离上次放出去玩也挺久,离下次放出去玩还不知道有多久... 好累啊...大脑基本成天在挂机了.什么也不想干了... 持续状态不佳.但是今天运气好,所以考试排名看起来还可以. T1没认真读题也没看数据范围,以为是送分题,17分钟写完交了...然后我就把分送出去了 像个弱智一样...但是现在的精神状态的确不太能支持好好做题 幸亏T2是个比较简单的SAM+dp,思维量不大,脑子宕机的时候也能写一写. (归功于当时给大家讲课时稍微有一点理解,要是其它的板子我

[考试反思]0117省选模拟10:争夺

T3出了一点锅,于是按IOI赛制打的. 可能也是这辈子唯一一次好好打的IOI赛制了. 提答,又沉里面了,进去就出不来.莫名的虚荣让我根本没有回头看传统题. 于是的确在T3的80%时间里一直单题rk1,然而其实很慌,剩下两道题又怎样? 运气好,T1特别水,T2数据水,T3用奇技淫巧多拿7分于是并列rk1了. 数组没清空丢了1分... 状态差的不行,一下午一道题都没改出来...咕到第二天也没改出来 于是在第二天考试的时候写完三个暴力之后终于把T2A了... 然后第二天考试就炸了,没什么好说的 T1:

[考试反思]0122省选模拟12:延迟

博客咕过了一年我也就忘了我考试状态了2333. T1是弱智题但是没想...写个暴力跑路了(时间不够,主要投在T2/3上了) 然而其实想到了一个乱搞,觉得能得分的概率不大,结果数据奇水完全不对的玩意还有20分,然而我并没有写... 然而T2写的是正解,虽说没有其他人的状压优秀,T了一个细节WA了一个拿了80分,凑合吧. 然后T3时间不多的时候写的,拿个暴力,想到了正解大概怎么写但是没有写,太恶心. 考后改题写了写,一下午就过去了...一晚上也就过去了...弄得跟我颓废了半天一样... 然而是真xx

[考试反思]0130省选模拟13:悔恨

0+30+20=50.rk8 关键在于: T1写错个变量名挂了100分 kxkxkxkx(激动的语无伦次) 考试过程?上来看T1,一个比较裸的基环树dp,断开环上一条边之后大概就是一个稍加改动的最大独立集. 思路不难想,细节倒是有一点,考场上调啊调啊过了样例又手模了各种数据都过了两个半小时之后很开心就扔了. 然后看T2/3啥都不会,写了俩随机化就走了. 然而T3随机化+贪心是可以AC的.正确性不知道...没写... 最后还有5分钟回T1,突然发现T1可以不是基环树而是基环树森林??? 啊修锅修锅

[考试反思]0220省选模拟27:怪异

怪异的一场考试.考的有点懵 $T1$正解是模拟,人人都能切,然而也没有多少人敢笃定这就是正解吧,常数和精度上下卡着,看运气的题了. $T2$想到了第二档分其实离正解就不远了但是时间不够没往下想.回$T1$卡常去了. $T3$不给状压分,于是猜到一条结论之后并不敢往下想... 然而最后$T1$也没有卡过,考后也在这破玩意上浪费了不少时间... 而且$T3$数据特别谁水暴力可以过,然而因为我不会决策点单调,所以学了学知识点,并没有用暴力水过... T1:飞行棋 大意:长度为$n$的序列,$m$人.每

[考试反思]0306省选模拟39:延续

俩原题.对于看视频课太匆忙的我来说,还是算俩新题吧. 为啥感觉最近总是考第$9$啊.最近这种名次的频率好高.. (好菜啊第$9$还学个啥呢啊脑子呢???这还翻个什么盘啊) 然而其实第$9$也是混来的. 最开始先看的$T1$发现好像是原题,但是印象不深,大概还记得第一步怎么做. 接着往后看,$T2$看起来像弱智题.$T3$的话又是原题,思路极其简单但是是$exSAM+LCT$写出来会暴毙.于是扔在最后. 然后回$T1$尝试回忆.然后就没有然后了.折腾来折腾去想了两个小时硬是没想到$dp$定义. 果

[考试反思]1219省选模拟3: 释怀

有些东西渐渐就远去了...不必挂念. 只有时间才拥有如此力量.我们能做的,唯有释怀. 这次的题格外顺手,大概是我的强项了. 但是考得还是不够好吧...感觉可以更高的 今天迎来了学了OI一年多比较重要的一个成就:(虽说是在考后) AC1000道题!还是挺不容易的. 第1000道题是今天的T3.大部分是自己思考的,题也不是很简单,挺好的. 挺过了联赛,现在想要等到下一次整百,可能就要到3月份了. 我还能在OI多久呢? 回到这场考试. T1的数据范围只有10000,让我想起了ALO那道题50000数据

[考试反思]0110省选模拟5:信仰

又倒一啦 10分真是个熟悉的成绩(虽然没有爆零熟悉) 状态一直低迷,没什么好说的 答题策略的话...就那样吧 一眼看出T1是结论题,没有部分分,不好写. 但T2是伯努利数的差不多是模板题了,于是就奔着它去了. 没有注意$0^0=1$.过不去样例最后交的暴力 没有抽时间认真打T3的暴力,因为至多30分. 因为现在30分和0分对我来说是一样的.我是要靠着省选翻盘,拿大众分的话肯定还是退役,求个稳,4个月白学. 现在的答题策略的确不能像联赛时一样了.现在求稳是赢不了了,在稳住200和争取230里我可能