标签:字符串 覆盖 got 技术 play opened onclick 重叠 pts
开心的像个孩子。
$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$。$n\le 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 }
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 }
标签:字符串 覆盖 got 技术 play opened onclick 重叠 pts
原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12628977.html