AtCoder Beginner Contest 215

文章目录


E - Chain Contestant

题意:
给你一个只有 10 10 10个大写字母长度为 n n n的字符串 s s s,问有多少种非空子序列,使得如果选了一个字符,那么这些字符必须连续出现

思路:状压dp
状态表示:
d p i , j , k dp_{i,j,k} dpi,j,k,表示枚举到第 i i i个字符,以 j j j结尾, k k k表示每字符选和不选的状态,例如 d p 4 , 3 , 0001001000 dp_{4,3,0001001000} dp4,3,0001001000表示当前枚举到第四个字符,以3为结尾,当前出现的字符集为3,6

状态转移:
c u r cur cur表示当前枚举的字符
1.当前不选这个字符,当前状态直接从之前状态转移
d p i , c u r , k = d p i − 1 , j , k   ( 0 ≤ j ≤ 9 )   ( 0 ≤ k ≤ 1023 ) dp_{i,cur,k}=dp_{i-1,j,k} \space (0\le j\le9)\space (0\le k\le 1023) dpi,cur,k=dpi1,j,k (0j9) (0k1023)
2.当前只选这个字符,与之前状态无关
d p i , c u r , 1 < < c u r + = 1 dp_{i,cur,1<<cur}+=1 dpi,cur,1<<cur+=1
3.在之前状态基础上选这个字符
想选这个字符,那么之前状态必须以 c u r cur cur结尾或者没有出现 c u r cur cur
如果 k k k的第 c u r cur cur位为 1 1 1 d p i , c u r , k + = d p i − 1 , c u r , k dp_{i,cur,k}+=dp_{i-1,cur,k} dpi,cur,k+=dpi1,cur,k
否则 d p i , c u r , k ∣ 1 < < c u r + = d p i − 1 , j , k ( j ≠ c u r ) dp_{i,cur,k|1<<cur}+=dp_{i-1,j,k} (j\neq cur) dpi,cur,k1<<cur+=dpi1,j,k(j=cur)
( k ∣ 1 < < c u r ) (k|1<<cur) (k1<<cur)表示把 k k k的第 c u r cur cur位变成 1 1 1

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define ll long long
#define int ll
#define pb push_back
#define mp make_pair
#define SZ(x) (int)(x.size())
#define ALL(x) (x).begin(),(x).end()
#define mst(a,x) memset(a,x,sizeof(a))
#define ls u<<1
#define rs u<<1|1
typedef vector<int> VI;
typedef pair<int,int> PII;
const int maxn=1e6+10;
const int mod=998244353;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;

int n;
char s[1010];
int dp[1010][11][1025];

void solve()
{
    cin>>n>>s+1;

    rep(i,1,n)
    {
        int cur=s[i]-'A';

        //不选这一位
        rep(j,0,9) rep(k,0,1023) dp[i][j][k]=dp[i-1][j][k];

        //只选这一位
        dp[i][cur][1<<cur]=(dp[i][cur][1<<cur]+1)%mod;

        rep(j,0,1023)
        {
            //字符集里有cur
            if(j>>cur&1)
            {
                dp[i][cur][j]=(dp[i][cur][j]+dp[i-1][cur][j])%mod;
            }
            else
            {
                rep(c,0,9)
                    if(c!=cur) //加上不以cur结尾的状态
                        dp[i][cur][j|1<<cur]=(dp[i][cur][j|1<<cur]+dp[i-1][c][j])%mod;
            }
        }
    }

    int ans=0;
    rep(j,0,9) rep(k,0,1023) ans=(ans+dp[n][j][k])%mod;
    cout<<ans<<endl;
}

signed main()
{
#ifdef LOCAL
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //int _;cin>>_;while(_--)
    solve();
    return 0;    
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值