• 【CF1487G】String Counting


    题目

    题目链接:https://codeforces.com/contest/1487/problem/G

    你有 (26) 个不同的字符,第 (i) 个字符有 (c_i) 个。
    你希望用这些字符,构造出一个字符串(每个字符在字符串中出现的个数不超过 (c_i)),使得这个字符串上不存在长度为奇数且大于 (1) 的回文串。求出方案数对 (998244353) 取模的结果。
    (nleq 400;frac{n}{3} < c_i leq n)

    思路

    显然等价于不存在两个位置 (i,i+2) 满足 (s_i=s_{i+2})
    这个 (c_i>frac{n}{3}) 意味着最多只有两个字符可能会超出限制,所以考虑容斥。
    (f[i][j][k][0/1/2][0/1/2]) 表示选到第 (i) 个位置,字符 (x) 出现 (j) 次,(y) 出现 (k) 次,第 (i-2,i-1) 位置的字符分别为 除 (x,y) 外的字符/字符 (x)/字符 (y) 的方案数。
    不用考虑字符 (x,y) 分别是什么,也不用考虑使用有没有超出 (c_x,c_y),只要求不存在两个位置 (i,i+2) 满足 (s_i=s_{i+2})
    这个东西大力分类讨论即可。注意当第 (i) 位填除 (x,y) 外的字符时,转移过来的权值可能为 (23)(24)
    然后记 (g[i][j]) 表示字符 (x) 使用至少 (i) 个,字符 (y) 使用至少 (j) 个的方案数。直接把 (f) 做一遍后缀和即可。
    容斥一下即可得到答案

    [g[0][0]-sum^{26}_{i=1}g[c_i+1][0]+sum^{26}_{i=1}sum^{26}_{j=i+1}g[c_i+1][c_j+1] ]

    (f) 数组滚动一下,时间复杂度 (O(n^3)),空间复杂度 (O(n^2))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=210,MOD=998244353;
    int n,ans,c[30],f[2][N][N][3][3],g[N][N];
    
    signed main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=26;i++)
    		scanf("%d",&c[i]);
    	f[0][0][0][0][0]=24*24;
    	f[0][1][0][1][0]=f[0][1][0][0][1]=f[0][0][1][0][2]=f[0][0][1][2][0]=24;
    	f[0][1][1][1][2]=f[0][1][1][2][1]=f[0][2][0][1][1]=f[0][0][2][2][2]=1;
    	for (int i=3;i<=n;i++)
    	{
    		int id=i&1;
    		memset(f[id],0,sizeof(f[id]));
    		for (int j=0;j<=n/2+1;j++)
    			for (int k=0;k<=n/2+1;k++)
    			{
    				f[id][j][k][0][0]=(23LL*f[id^1][j][k][0][0]+24LL*f[id^1][j][k][1][0]+24LL*f[id^1][j][k][2][0])%MOD;
    				f[id][j][k][1][0]=(23LL*f[id^1][j][k][0][1]+24LL*f[id^1][j][k][1][1]+24LL*f[id^1][j][k][2][1])%MOD;
    				f[id][j][k][2][0]=(23LL*f[id^1][j][k][0][2]+24LL*f[id^1][j][k][1][2]+24LL*f[id^1][j][k][2][2])%MOD;
    				if (j) f[id][j][k][0][1]=(f[id^1][j-1][k][0][0]+f[id^1][j-1][k][2][0])%MOD;
    				if (j) f[id][j][k][1][1]=(f[id^1][j-1][k][0][1]+f[id^1][j-1][k][2][1])%MOD;
    				if (j) f[id][j][k][2][1]=(f[id^1][j-1][k][0][2]+f[id^1][j-1][k][2][2])%MOD;
    				if (k) f[id][j][k][0][2]=(f[id^1][j][k-1][0][0]+f[id^1][j][k-1][1][0])%MOD;
    				if (k) f[id][j][k][1][2]=(f[id^1][j][k-1][0][1]+f[id^1][j][k-1][1][1])%MOD;
    				if (k) f[id][j][k][2][2]=(f[id^1][j][k-1][0][2]+f[id^1][j][k-1][1][2])%MOD;
    			}
    	}
    	for (int i=n/2+1;i>=0;i--)
    		for (int j=n/2+1;j>=0;j--)
    		{
    			ll sum=0;
    			for (int k=0;k<=8;k++)
    				sum=(sum+f[n&1][i][j][k/3][k%3])%MOD;
    			g[i][j]=(sum+g[i+1][j]+g[i][j+1]-g[i+1][j+1])%MOD;
    		}
    	ans=g[0][0];
    	for (int i=1;i<=26;i++)
    		if (c[i]+1<N) ans=(ans-g[c[i]+1][0])%MOD;
    	for (int i=1;i<=26;i++)
    		for (int j=i+1;j<=26;j++)
    			if (max(c[i],c[j])+1<N)
    				ans=(ans+g[c[i]+1][c[j]+1])%MOD;
    	printf("%d",(ans%MOD+MOD)%MOD);
    	return 0;
    }
    
  • 相关阅读:
    IOS技能点之Foundation之NSString
    JavaScript学习笔记 -- ES6学习(二) let 和const
    JavaScript 学习笔记-- ES6学习(一)介绍以及Babel的使用
    JavaScript 学习笔记: 扩充类型的功能
    PHP学习笔记(八)
    PHP学习笔记(六)
    Less 官方文档学习笔记
    PHP学习笔记(五)
    PHP 学习笔记 (四)
    PHP 学习笔记 (三)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14764394.html
Copyright © 2020-2023  润新知