【题解】ABC 209

E.

题意:给定一个初始字符串,可以把它接龙下去,最后无法操作的人判负。若双方都采用最优策略,即先保证自己不输,再击败对方,输出博弈结果。 n<=2e5

Solution:

这是一道图论的博弈问题,考虑回溯 + 逆推。

首先这个平局很难判断,我们不妨先求出必胜或必败的状态,如果两者都不是,则说明是平局状态。首先初度为零是必败态,其次,如果后继有一个必败态,则它为必胜态;如果后继全为必胜态,则它为必败态。

这个环比较难搞,不妨看下图:

在这里插入图片描述

这是环上都有值的情况。有时候会形成一个封闭的环,双方都不愿意走出这个环,否则都是自己输,如下图:
在这里插入图片描述

那么此时环上的状态都是平局了。

最后考虑优化建边,不难想到将首和尾连边,这样出发点就是尾字符。

时间复杂度 O(n)

#include<bits/stdc++.h> #define ins insert #define mp make_pair #define pii pair<int,int> #define pb push_back #define vec vector using namespace std; const int mx=2e5+5; const int mxn=52*52*52; int n,m,dp[mxn],deg[mxn]; string s; vec<int> son[mx]; pii edge[mx]; queue<int> Q; int char_to_int(char c) { if('A'<=c&&c<='Z') return c-'A'; else return c-'a'+26; } int string_to_int(string s) { for(auto &c:s) { c=char_to_int(c); } return s[0]*52*52+s[1]*52+s[2]; } //思路:回溯+逆推 int main() { // freopen("data.in","r",stdin); memset(dp,-1,sizeof(dp)); ios_base::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++) { cin>>s; int x=string_to_int(s.substr(0,3)),y=string_to_int(s.substr(s.size()-3,3)); // cout<<x<<" "<<y<<endl; edge[i]=mp(x,y); son[y].pb(x),deg[x]++; // appear[id[i]]=1; } int Lose=0,Win=1; for(int i=0;i<mxn;i++) { if(!deg[i]) { dp[i]=Lose; Q.push(i); } } while(Q.size()) { int x=Q.front(); Q.pop(); if(dp[x]==Win) { for(auto y:son[x]) { if(~dp[y]) continue; if(--deg[y]==0) { dp[y]=Lose; Q.push(y); } } } else { for(auto y:son[x]) { if(~dp[y]) continue; dp[y]=Win; Q.push(y); } } } for(int i=1;i<=n;i++) { if(dp[edge[i].second]==Lose) cout<<"Takahashi"<<endl; else if(dp[edge[i].second]==Win) cout<<"Aoki"<<endl; else cout<<"Draw"<<endl; } }

F.

题意:给定 n 个数以及高度,砍掉一棵树的代价为 h[i-1]+h[i]+h[i+1] ,同时令 h[i]=0 。求一个砍树的排列,使得总花费最少。求排列的个数。

Solution:

考虑每一棵树 i,如果它相邻的树比它先砍,则自己每次要增加代价 h[i]

这样,对于 1<=i<=n-1 ,如果 h[i]<h[i+1] ,则 i+1 先砍最优;如果 h[i]>h[i+1] ,则 i 先砍最优。

那么令 dp[i][j]i 棵树的所有排列数,使得树 i 是要砍掉的第 j 个元素 ,这里有隐含条件 j<=i 。不难写出转移式,通过前缀和优化,时间复杂度 O(n^2)

这种为每个转换插入元素的 DP 结构称为“插入 DP”。

#include<bits/stdc++.h> #define ll long long #define ins insert #define mp make_pair #define pii pair<int,int> #define pb push_back #define vec vector using namespace std; const int mx=4005; const int mod=1e9+7; ll dp[mx][mx],res; int n,a[mx]; //dp[i][j] 前 i 棵树的所有排列数,使得树 i 是要砍掉的第 j 个元素 int main() { // freopen("data.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } dp[1][1]=1; for(int i=2;i<=n;i++) { for(int j=1;j<=i;j++) { if(a[i-1]<a[i]) { dp[i][j]=(dp[i][j]+dp[i-1][i-1]-dp[i-1][j-1])%mod; } else if(a[i-1]>a[i]) { dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod; } else { dp[i][j]=(dp[i][j]+dp[i-1][i-1])%mod; } dp[i][j]=(dp[i][j]+dp[i][j-1])%mod; // printf("dp[%d][%d]=%d\n",i,j,dp[i][j]); } } res=dp[n][n]; if(res<0) res+=mod; printf("%lld",res); }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530328.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(13)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示