【XSY3990】Alice 和 Bob 双在玩游戏(博弈,dp,拓扑,背包)

7 篇文章 0 订阅
4 篇文章 0 订阅

题面

Alice 和 Bob 双在玩游戏

题解

注意到这里一个人无法操作后,另一个人也不一定无法操作(即不像普通的取石子游戏一样),所以考虑转化一下他们各自的最优策略:双方都想让自己比对方尽可能多移动一些步。

然后注意到每一颗石子都是相互独立的,即一个点上多一颗石子不会影响其他石子。

所以考虑设 f i f_i fi 表示:若在 i i i 节点上多放一颗棋子,在双方都使用最优策略的情况下,Alice 能比 Bob 最多多走多少步。( f i f_i fi 可能是负数,因为 i i i 节点的颜色是不确定的)

容易得到转移方程:

f u = { max ⁡ ( 0 , max ⁡ ( u , v ) f v + 1 ) if  c o l u = white ⁡ min ⁡ ( 0 , min ⁡ ( u , v ) f v − 1 ) if  c o l u = black ⁡ f_u= \begin{cases} \max(0,\max\limits_{(u,v)}f_v+1)&\text{if }col_u=\operatorname{white}\\ \min(0,\min\limits_{(u,v)}f_v-1)&\text{if }col_u=\operatorname{black}\\ \end{cases} fu=max(0,(u,v)maxfv+1)min(0,(u,v)minfv1)if colu=whiteif colu=black

要对 0 0 0 max ⁡ / min ⁡ \max/\min max/min 是因为我可以选择不移动新增加的这一枚棋子,这样相当于没有变化。

那么直接建反向图拓扑排序转移即可。

然后题目问的其实是在在双方都使用最优策略的情况下,有多少种情况使得 Alice 比 Bob 多走的步数为正数。

然后现在每一个节点如果放了棋子对多走的步数的贡献也已经算出来了(即 f i f_i fi),所以背包转移即可。

代码如下:

#include<bits/stdc++.h>
 
#define N 310
 
using namespace std;
 
namespace modular
{
    const int mod=998244353;
    inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
    inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;
 
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}
 
int n,m,deg[N];
int cnt,head[N],to[N*N],nxt[N*N];
int f[N],dp[N][N*N*2];
char s[N];
bool col[N];
 
queue<int>q;
 
void adde(int u,int v)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    head[u]=cnt;
}
 
void tuopu()
{
    for(int i=1;i<=n;i++)
        if(!deg[i]) q.push(i);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(col[v]) f[v]=min(f[v],f[u]-1);
            else f[v]=max(f[v],f[u]+1);
            deg[v]--;
            if(!deg[v]) q.push(v);
        }
    }
}
 
int main()
{
    n=read(),m=read();
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
        col[i]=(s[i]=='B');
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read();
        adde(v,u),deg[u]++;
    }
    tuopu();
    dp[0][n*n]=1;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<=n*n*2;j++)
        {
            if(!dp[i][j]) continue;
            dp[i+1][j+f[i+1]]=add(dp[i+1][j+f[i+1]],dp[i][j]);
            dp[i+1][j]=add(dp[i+1][j],dp[i][j]);
        }
    }
    int ans=0;
    for(int i=n*n+1;i<=n*n*2;i++)
        ans=add(ans,dp[n][i]);
    printf("%d\n",ans);
    return 0;
}
/*
5 4
wwwww
1 2
2 3
3 4
4 5
*/
/*
10 15
BWBWBBWWBW
1 2
1 5
1 10
2 6
2 8
3 6
3 7
4 10
5 6
5 7
5 8
6 8
6 9
7 10
8 9
*/
根据提供的引用内容,你遇到的问题是在发送HTTP POST请求时收到了403 Forbidden的错误。这个错误通常表示你没有权限访问所请求的资源。 要解决这个问题,你可以采取以下步骤: 1. 首先,确保你的请求URL正确,并且你有权限访问该URL。你可以尝试在浏览器中直接访问该URL,看看是否能够成功访问。 2. 如果你确定URL是正确的,并且你有权限访问,那么可能是你的请求中缺少了必要的身份验证信息。你可以检查你的请求头中是否包含了正确的身份验证信息,比如Token或用户名密码。 3. 另外,你还可以检查服务器端的配置,确保你的请求被正确地处理和授权。你可以查看服务器的日志,以了解更多关于403错误的详细信息。 综上所述,当你收到403 Forbidden错误时,你应该首先检查URL和权限,然后确保请求中包含了正确的身份验证信息。如果问题仍然存在,你可以进一步检查服务器端的配置和日志,以找出问题的根本原因。 #### 引用[.reference_title] - *1* [kubeadm init报错10248...(The HTTP call equal to ‘curl -sSL http://localhost:10248/healthz‘ failed)](https://blog.csdn.net/weixin_45969972/article/details/123529966)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [c/c++使用libcurl库做http客户端及封装(HTTP_GET和HTTP_POST)](https://blog.csdn.net/xsy29000/article/details/103181267)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值