[考试反思]0403省选模拟61:快乐

Posted hzoi-deepinc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[考试反思]0403省选模拟61:快乐相关的知识,希望对你有一定的参考价值。

技术图片

技术图片

开心的像个孩子。

$T2$神赐的数据,乱搞能拿到$80$。(其实再加两条特判就能$AC$

$T1$是$dy$原题。总算没有翻车。

$T2$的话,我研究了一会,没什么思路于是开始乱搞。

于是直接输出答案的上界,结果过了大样例,就交了。

$T3$的话,题目描述有误+自己没看清题,写了个$15pts$的暴力结果爆零了。

赶巧小样例答案是无解大样例又太大,完全没意识到自己读错理解错。

其实思路已经有了,但是看错题之后就完全不可做了,白瞎我想了半天。

 

T1:GTM

https://www.cnblogs.com/hzoi-DeepinC/protected/p/12323822.html

(Code:4)第8题。

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 200005
 4 #define mod 66662333
 5 struct pt{int x,v;friend bool operator<(pt a,pt b){return a.v<b.v;}}P[S];
 6 struct sg{int l,r;friend bool operator<(sg a,sg b){return a.l<b.l||(a.l==b.l&&a.r<b.r);}}L[S];
 7 int n,t[S],cnt; map<int,int>M;
 8 int mo(int x){return x>=mod?x-mod:x;}
 9 void Add(int p,int v){for(;p<=n+1;p+=p&-p)t[p]=min(t[p],v);}
10 int Ask(int p,int a=n){for(;p;p^=p&-p)a=min(a,t[p]);return a;}
11 void ADD(int p,int v){for(;p<=n+1;p+=p&-p)t[p]=max(t[p],v);}
12 int ASK(int p,int a=1){for(;p;p^=p&-p)a=max(a,t[p]);return a;}
13 void add(int p,int v){for(;p<=n+1;p+=p&-p)t[p]=mo(t[p]+v);}
14 int ask(int p,int a=0){for(;p;p^=p&-p)a=mo(a+t[p]);return a;}
15 int main(){
16     cin>>n;
17     for(int i=1;i<=n;++i)scanf("%d%d",&P[i].x,&P[i].v),t[i]=P[i].x;
18     sort(P+1,P+1+n); sort(t+1,t+1+n);
19     for(int i=1;i<=n;++i)M[t[i]]=i,t[i]=n;
20     for(int i=1;i<=n;++i)Add(n+1-M[P[i].x],i),L[i].l=Ask(n+1-M[P[i].x]);
21     for(int i=1;i<=n;++i)t[i]=1;
22     for(int i=n;i;--i)ADD(M[P[i].x],i),L[i].r=ASK(M[P[i].x]);
23     for(int i=1;i<=n;++i)t[i]=0;
24     sort(L+1,L+1+n); t[n+1]=1;
25     for(int i=1;i<=n;++i)add(n+1-L[i].r,ask(n+2-L[i].l));
26     cout<<t[1]<<endl;
27 }
我才知道树状数组可以倒着写,然而并没有写

 

T2:字符串游戏

大意:给定字符串。$S_0,T$。第$i$轮操作可以使$S_{i,j}$成为$S_{i,j-1}$或$S_{i-1,j}$。求最少多少次操作能使$S=T$。$nle 10^6$

我们依次把$S_0,S_1...S_x$列出来。发现操作就是,从$T$出发,每次只能往上或往左走,最后要走到$S$中的相同字符,路径可以合并不可交叉,要求行数尽量少。

贪心而言,越晚转弯越好。我们对于每个$T$的极长相同段,找到更靠前的$S$的第一次出现,这段区间就都是被横着走所覆盖的。

我们只需要知道对于每个位置,有多少个不重叠的横着走的,答案对此取$max$即可。

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int ans,n;char t[1000005],s[1000005];
 4 int main(){
 5     scanf("%d%s%s",&n,s+1,t+1);
 6     for(int i=1;i<=n;++i)if(s[i]!=t[i])goto x;
 7     return puts("0"),0;x:
 8     for(int i=n;i>0;--i){
 9         int f=0,sp=i,tp;
10         re:f++;tp=i;
11         while(sp&&s[sp]!=t[i])sp--;
12         while(tp>=sp&&t[tp]==t[i])tp--;tp++;
13         if(!sp)return puts("-1"),0;
14         i=tp-1;
15         if(sp==tp)ans=max(ans,f);
16         else goto re;
17     }cout<<ans<<endl;
18 }
View Code

 

T3:ACE

大意:一个$k$点$m$边的无向图,将这个图复制成$n$份。对于新的$nk$个点的图的补图,问有多少种哈密顿路径(不是回路)。$k le 14,n le 50000$

题目其实也就是在说,不能经过原图里的任何边。

这个我们不会求,于是我们求它经过了多少补图的边。

对于任意一条哈密顿路径,我们考虑,每两条补图边之间,一定是一条「在其中一份原图的路径」(单独一个点也视为一条路径)

那么我们可以得知:补图边数=原图路径数-1

然后我们就可以据此求出所有哈密顿路径的原图路径数(直接求不好求,我们可以利用“至少”,也就是说,两个原图路径之间,可能也是原图路径)

通过容斥得到补图边数恰好$=n*k-1$的总方案数。

接下来在原图上,对于

首先通过简单$dp$可以得到$f[s]$表示用原图的一条路径经过点集$s$的方案数

然后做一个背包$dp$得到$dp[i]$表示用$i$条原图路径恰好覆盖满所有点的方案数(顺序不同计做不同方案)

我们对$dp$做一个指数型生成函数就完事了。

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 998244353
 4 int mo(int x){return x>=mod?x-mod:x;}
 5 int n,k,m,mp[15][15],dp[1<<15][15],f[1<<15],g[15][1<<15],ans,len,rev[1<<21],A[1<<21],fac[1<<21],finv[1<<21];
 6 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
 7 void sat(int l){
 8     len=1;while(len<=l)len<<=1;
 9     for(int i=1;i<len;++i)rev[i]=rev[i>>1]>>1|(i&1?len>>1:0);
10 }
11 void NTT(int*a,int op){
12     for(int i=1;i<len;++i)if(rev[i]>i)swap(a[i],a[rev[i]]);
13     for(int i=1;i<len;i<<=1)for(int j=0,w=qp(3,(mod-1)/2/i*op+mod-1);j<len;j+=i<<1)
14         for(int k=j,t=1,x,y;k<j+i;++k,t=1ll*t*w%mod)
15             x=a[k],y=1ll*a[k+i]*t%mod,a[k]=mo(x+y),a[k+i]=mo(x-y+mod);
16     if(op==-1)for(int i=0,iv=qp(len,mod-2);i<len;++i)a[i]=1ll*a[i]*iv%mod;
17 }
18 int main(){//freopen("wings.in","r",stdin);
19     cin>>n>>k>>m;
20     for(int i=1,a,b;i<=m;++i)scanf("%d%d",&a,&b),mp[a][b]=mp[b][a]=1;
21     const int mst=(1<<k)-1;
22     for(int s=1;s<=k;++s)dp[1<<s-1][s]=1;
23     for(int x=1;x<=mst;++x)for(int t=1;t<=k;++t)if(dp[x][t]){
24         for(int j=1;j<=k;++j)if(mp[t][j]&&!(x&1<<j-1))dp[x|1<<j-1][j]=mo(dp[x|1<<j-1][j]+dp[x][t]);
25         f[x]=mo(f[x]+dp[x][t]);
26     }
27     g[0][0]=1;// for(int i=1;i<=mst;++i)cerr<<f[i]<<endl;
28     for(int i=1;i<=k;++i)for(int s=1;s<=mst;++s)for(int e=s;e;e=e-1&s)g[i][s]=(g[i][s]+1ll*g[i-1][s^e]*f[e])%mod;
29     sat(n*k);
30     for(int i=fac[0]=1;i<=n*k;++i)fac[i]=1ll*fac[i-1]*i%mod;
31     finv[n*k]=qp(fac[n*k],mod-2);
32     for(int i=n*k-1;~i;--i)finv[i]=finv[i+1]*(i+1ll)%mod;
33     for(int i=1;i<=k;++i)A[i]=g[i][mst]*1ll*finv[i]%mod;
34     NTT(A,1);
35     for(int i=0;i<len;++i)A[i]=qp(A[i],n);
36     NTT(A,-1);
37     for(int i=1;i<=n*k;++i)ans=(ans+1ll*fac[i]*(n*k-i&1?mod-A[i]:A[i]))%mod;
38     cout<<ans<<endl;
39 }
View Code

以上是关于[考试反思]0403省选模拟61:快乐的主要内容,如果未能解决你的问题,请参考以下文章

[考试反思]0131省选模拟测14:遗失

[考试反思]0214省选模拟24:揣测

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

[考试反思]0212省选模拟23:迷失

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

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