cf1620g Subsequences Galore
给定一个字符串序列 , 定义 为至少是其中一个字符串 的子序列的字符串个数,其中 .
给定哟个字符串序列 对每一个子集 求出 对 取模后的值。
输出 的异或和(不取模)。
注意每个字符串 中的字母都是排好序的。
正着求 很难,考虑反着,那就是 容斥 !
用 表示字符串集合为 时,在 中每一个集合都出现的字符串个数 . 此时的时间复杂度为 ,这个大概在 左右,时限是 10s ,可以跑过去 .
对于每个 可以通过枚举子集以 的时间复杂度求出,此时这个做法的时间复杂度就是 . 很显然,过不去 .
code
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline") //Optimization flags
#pragma GCC option("arch=native","tune=native","no-zero-upper") //Enable AVX
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#include<bits/stdc++.h>
using namespace std;
char in[1000005];
int iiter=0,llen=0;
inline char get(){
if(iiter==llen)llen=fread(in,1,100000,stdin),iiter=0;
if(llen==0)return EOF;
return in[iiter++];
}
inline int rd(){
char ch=get();while(ch<'0'||ch>'9')ch=get();
int res=0;while(ch>='0'&&ch<='9')res=(res<<3)+(res<<1)+ch-'0',ch=get();
return res;
}
inline void pr(long long res){
if(res==0){putchar('0');return;}
static int out[20];int len=0;
while(res)out[len++]=res%10,res/=10;
for(int i=len-1;i>=0;i--)putchar(out[i]+'0');
}
inline string getstr(){
char ch=get();string res="";
while(isspace(ch))ch=get();
while(!isspace(ch))res+=ch,ch=get();
return res;
}
const int mod=998244353;
int n;
string s[24];
int builtin_popcount[1<<24];
int f[1<<24],g[1<<24];
int cnt[24][30];
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
n=rd();
for(int i=0;i<n;i++)s[i]=getstr();
for(int msk=0;msk<(1<<n);msk++){
int tmp=0;
for(int i=0;i<n;i++)if(msk&(1<<i))tmp++;
builtin_popcount[msk]=tmp;
}
for(int i=0;i<n;i++){
for(int j=0;j<(int)s[i].size();j++)
cnt[i][s[i][j]-'a']++;
}
for(int msk=0;msk<(1<<n);msk++)f[msk]=1;
for(int msk=1;msk<(1<<n);msk++){
int mx[26];memset(mx,0x3f3f3f3f,sizeof(mx));
for(int i=0;i<n;i++)if(msk&(1<<i))
for(int j=0;j<26;j++)mx[j]=min(mx[j],cnt[i][j]);
for(int i=0;i<26;i++)f[msk]=1ll*f[msk]*(mx[i]+1)%mod;
}
for(int msk=0;msk<(1<<n);msk++)f[msk]=(f[msk]-1+mod)%mod;
memset(g,0,sizeof(g));
for(int msk=0;msk<(1<<n);msk++){
for(int sub=msk;;sub=(sub-1)&msk){
if(builtin_popcount[sub]&1)g[msk]=(g[msk]+f[sub])%mod;
else g[msk]=(g[msk]-f[sub]+mod)%mod;
if(sub==0)break;
}
}
long long ans=0;
for(int msk=0;msk<(1<<n);msk++){
long long tmp=0;
for(int i=0;i<n;i++)if(msk&(1<<i))tmp+=i+1;
tmp=1ll*tmp*builtin_popcount[msk]*(g[msk]+1);
ans=ans^tmp;
}
pr(ans);
return 0;
}
/*inline? ll or int? size? min max?*/
但是此时,通过仔细思考,可以发现,在复杂度瓶颈 的地方 .
for(int msk=0;msk<(1<<n);msk++){
for(int sub=msk;;sub=(sub-1)&msk){
if(builtin_popcount[sub]&1)g[msk]=(g[msk]+f[sub])%mod;
else g[msk]=(g[msk]-f[sub]+mod)%mod;
if(sub==0)break;
}
}
当 是偶数的时候,将 取反,那么 就等于子集相加,可以用高维前缀和做到 . 于是将 优化到 .
时间复杂度 :
空间复杂度 :
code
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline") //Optimization flags
#pragma GCC option("arch=native","tune=native","no-zero-upper") //Enable AVX
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#include<bits/stdc++.h>
using namespace std;
char in[1000005];
int iiter=0,llen=0;
inline char get(){
if(iiter==llen)llen=fread(in,1,100000,stdin),iiter=0;
if(llen==0)return EOF;
return in[iiter++];
}
inline int rd(){
char ch=get();while(ch<'0'||ch>'9')ch=get();
int res=0;while(ch>='0'&&ch<='9')res=(res<<3)+(res<<1)+ch-'0',ch=get();
return res;
}
inline void pr(long long res){
if(res==0){putchar('0');return;}
static int out[20];int len=0;
while(res)out[len++]=res%10,res/=10;
for(int i=len-1;i>=0;i--)putchar(out[i]+'0');
}
inline string getstr(){
char ch=get();string res="";
while(isspace(ch))ch=get();
while(!isspace(ch))res+=ch,ch=get();
return res;
}
const int mod=998244353;
int n;
string s[24];
int builtin_popcount[1<<24];
int f[1<<24];
int cnt[24][30];
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
n=rd();
for(int i=0;i<n;i++)s[i]=getstr();
for(int msk=0;msk<(1<<n);msk++){
int tmp=0;
for(int i=0;i<n;i++)if(msk&(1<<i))tmp++;
builtin_popcount[msk]=tmp;
}
for(int i=0;i<n;i++){
for(int j=0;j<(int)s[i].size();j++)
cnt[i][s[i][j]-'a']++;
}
for(int msk=0;msk<(1<<n);msk++)f[msk]=1;
for(int msk=1;msk<(1<<n);msk++){
int mx[26];memset(mx,0x3f3f3f3f,sizeof(mx));
for(int i=0;i<n;i++)if(msk&(1<<i))
for(int j=0;j<26;j++)mx[j]=min(mx[j],cnt[i][j]);
for(int i=0;i<26;i++)f[msk]=1ll*f[msk]*(mx[i]+1)%mod;
}
for(int msk=0;msk<(1<<n);msk++){
f[msk]=(f[msk]-1+mod)%mod;
if(builtin_popcount[msk]&1)continue;
f[msk]=(mod-f[msk])%mod;
}
for(int i=0;i<n;i++){
for(int msk=0;msk<(1<<n);msk++)if(msk&(1<<i))
f[msk]=(f[msk^(1<<i)]+f[msk])%mod;
}
long long ans=0;
for(int msk=0;msk<(1<<n);msk++){
long long tmp=0;
for(int i=0;i<n;i++)if(msk&(1<<i))tmp+=i+1;
tmp=1ll*tmp*builtin_popcount[msk]*(f[msk]+1);
ans=ans^tmp;
}
pr(ans);
return 0;
}
/*inline? ll or int? size? min max?*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】