3 条题解

  • 3
    @ 2026-8-28 15:21:43

    注意到n<=18,我将用最直白,最易懂,最不绕弯子的方式告诉你,看到这个范围十有八九是状态压缩的题。

    根据乘法原理,单个字符串s[i]s[i]的贡献是pow(len(s[i]),L)pow(len(s[i]),L)(因为有LL个位置可以填,每个位置都有len(s[i])len(s[i])种选择),但是我们并不能简单地把贡献加起来,因为可能有2个字符串都能产生相同的答案,比如:

    S1=ahdgncksyuroS1=ahdgncksyuro S2=osuhayrcgS2=osuhayrcg L=3L=3

    注意到ans=gayans=gay或者urgayurgay会在这两个字符串的贡献中,因此需要减去重复的这一部分。

    重复的部分有多少呢?如果要同时出现在两个串的贡献中,他的字符必须是两个字符串所共有的,也就是交集。

    重复这个操作,观察规律(或者灵光一现)不难发现,在每一个n个字符串的子集中,若包含偶数个字符串,则减去贡献,否则加上贡献,据此状压并计算即可。

    戴马:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=18,M=30,mod=998244353;
    char s[N][M];
    int qpow(int a,int b){
    	int res=1;
    	for(;b;b/=2,a=a*a%mod)if(b&1)res=res*a%mod;
    	return res;
    }
    signed main(){
    	int n,l;scanf("%lld%lld",&n,&l);
    	for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
    	int ans=0;
    	for(int i=1;i<(1<<n);i++){
    		int v[M];memset(v,0,sizeof(v));
    		int sum=0,jj=0;
    		for(int j=1;j<=n;j++)if(i&(1<<(j-1))){
    			sum++;for(int k=1;k<=strlen(s[j]+1);k++)v[s[j][k]-'a'+1]++;
    		}
    		for(int j=1;j<=26;j++)if(v[j]==sum)jj++;
    		if(sum%2==1)ans+=qpow(jj,l),ans%=mod;
    		else ans-=qpow(jj,l),ans%=mod,ans+=mod,ans%=mod;
    	}
    	printf("%lld\n",ans);
    	return 0;
    } 
    

    我觉得你们应该看得懂。

    • 2
      @ 2026-8-28 14:15:36

      又一次注意到n18n\leq 18,每日随便造。

      思路

      不难发现,如果只有一层,很明显答案数就是可以使用的字母种类数的ll次方。

      但是如果有多层,答案就会有重复,考虑使用容斥去重。鉴于n18n\leq 18,不妨枚举那些层的键盘拥有一样的建,再将这些键可以造成的贡献容斥一下,最后统计答案即可。

      (此题可以用bitset优化,但是本蒟蒻并没有用,可以看看那些巨佬可以优化一下)

      AC代码

      #include<bits/stdc++.h>
      #define int long long
      using namespace std;
      const int N=30,P=998244353;
      int qpow(int a,int b)
      {
      	int res=1;
      	for(;b;b>>=1,a=a*a%P)if(b&1)res=res*a%P;
      	return res;
      }
      int getcnt(int a)//统计a中有多少个二进制位是1 
      {
      	int cnt=0;
      	while(a)
      	{
      		cnt++;
      		a-=a&-a;
      	}
      	return cnt;
      }
      int calcid(int x)//计算他有几位(相当于log) 
      {
      	int cnt=0;
      	while(x)cnt++,x>>=1;
      	return cnt;
      }
      char s[N];
      int a[N],n,l,c[N][N];
      signed main()
      {
      	scanf("%lld%lld",&n,&l);
      	for(int i=1;i<=n;i++)
      	{
      		scanf("%s",s+1);
      		int len=strlen(s+1);
      		for(int j=1;j<=len;j++)a[i]|=(1<<s[j]-'a');//状态压缩一下有那些键 
      	}
      	int ans=0;
      	for(int i=1;i<(1<<n);i++)//枚举每种状态 
      	{
      		int xxx=i,x=(1<<26)-1;
      		while(xxx)
      		{
      			int pos=xxx&-xxx;//必须是共同的按键,所以是& 
      			x&=a[calcid(pos)];
      			xxx-=xxx&-xxx;
      		}
      		int f,cntx=getcnt(x);
      		if(getcnt(i)&1)f=1;//奇数个 
      		else f=-1;//偶数个 
      		ans=((ans+f*qpow(cntx,l)%P)%P+P)%P;
      	}
      	printf("%lld\n",ans);
      	return 0;//完结撒花~ 
      }
      
      • 2
        @ 2026-8-28 14:05:55

        在单独指定字符集与长度时答案是很好算的,但在这里有可能会使能同时被两个字符集表示出来的字符串(显然就是能被两个字符集的并集表示出来的字符串),但减去后又会少考虑能同时被三个字符集表示出来的字符串...

        发现这和容斥原理非常像,同时注意到 nn 特别小,所以考虑容斥。

        #include<bits/stdc++.h>
        using namespace std;
        bitset<30> bit[20];
        const int mod=998244353;
        int count(int x){
        	int ji=0;
        	while(x){
        		ji++;
        		x=x&(x-1);
        	}
        	return ji;
        }
        long long power(long long a,long long b){
        	long long ans=1;
        	while(b){
        		if(b&1)ans=ans*a%mod;
        		a=a*a%mod;
        		b>>=1;
        	}
        	return ans;
        }
        int main(){
        	int n,l;
        	cin>>n>>l;
        	for(int i=1;i<=n;i++){
        		string s;
        		cin>>s;
        		for(int j=0;j<int(s.size());j++){
        			bit[i][s[j]-'a'+1]=1;
        		}
        	}
        	long long ans=0;
        	for(int s=1;s<(1<<n);s++){
        		bitset<30> now((1<<30)-1);
        		for(int j=1;j<=n;j++)if((s>>(j-1))&1)now&=bit[j];
        		ans+=(count(s)%2?1:-1)*(power(now.count(),l));
        		ans+=mod;
        		ans%=mod;
        	}
        	cout<<ans;
        	return 0;
        }
        
        • 1

        信息

        ID
        12445
        时间
        2000ms
        内存
        1024MiB
        难度
        8
        标签
        递交数
        11
        已通过
        8
        上传者