[COCI2021-2022#1] Kamenčići 解题记录

[COCI2021-2022#1] Kamenčići 解题记录


题意简述

一个长度为 N N N 的字符串 S S S,仅由 CP 组成。轮流每次从两端取出一个字符,先取出 K K KC 的失败,求先手必胜还是必败。


题目分析

考虑区间 DP,设 d p l , r , k dp_{l,r,k} dpl,r,k 表示取到还剩区间 [ l , r ] [l,r] [l,r],当前轮到的人已经取了 k k kC,当前状态是必胜还是必败。
因为只剩一个石子的状态是确定的,所以区间从少往多转移,即区间 [ l , r ] [l,r] [l,r] 从区间 [ l + 1 , r ] [l+1,r] [l+1,r] [ l , r − 1 ] [l,r-1] [l,r1] 转移。
下一个取得的数量 t t t 怎么求?
假设我们取到了 [ l , r ] [l,r] [l,r],并且当前有 k k kC 被取了,那么 t t t 就是区间 [ l − 1 , r + 1 ] [l-1,r+1] [l1,r+1]C 的数量减去现在的 k k k,用前缀和维护。
由于相邻的两个状态相反,所以转移的时候需要取反。
状态转移方程:
d p l , r , k = ¬   d p l + 1 , r , t ∨ ¬   d p l , r − 1 , t dp_{l,r,k}=\lnot \ dp_{l+1,r,t} \vee \lnot \ dp_{l,r-1,t} dpl,r,k=¬ dpl+1,r,t¬ dpl,r1,t


AC Code
#include<bits/stdc++.h>
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]<<" "
#define arrin(a,n) rep(i,1,n)std::cin>>a[i]
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dep(i,x,n) for(int i=x;i>=n;i--)
#define erg(i,x) for(int i=head[x];i;i=e[i].nex)
#define dbg(x) std::cout<<#x<<":"<<x<<" "
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define u_b upper_bound
#define l_b lower_bound
#define p_b push_back
#define CD const double
#define CI const int
#define int long long
#define il inline
#define ss second
#define ff first
#define itn int
CI N=355;
int32_t n,K,dp[N][N][N/2],sum1[N],sum2[N];
std::string s;
int dfs(int l,int r,int k){
    if(dp[l][r][k]!=-1){
        return dp[l][r][k];
    }
    if(k>=K){
        return 0;
    }
    int t=sum1[l-1]+sum2[r+1]-k;
    if(t>=K){
        return 1;
    }
    int ans=(!dfs(l+1,r,t)|!dfs(l,r-1,t));
    return dp[l][r][k]=ans;
}
signed main() {
    std::cin>>n>>K>>s;
    s=" "+s;
    mem(dp,-1);
    rep(i,1,n){
        sum1[i]=sum1[i-1]+(s[i]=='C');
    }
    dep(i,n,1){
        sum2[i]=sum2[i+1]+(s[i]=='C');
    }
    if(dfs(1,n,0)){
        puts("DA");
    }else{
        puts("NE");
    }
    return 0;
}
  • 18
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值