AC修炼计划(AtCoder Regular Contest 164)

传送门:AtCoder Regular Contest 164 - AtCoder

A.签到题,在此不做赘述

B - Switching Travel

AC修炼计划(AtCoder Regular Contest 164)_第1张图片

这题本来该是秒的,但是因为没有考虑清楚环的问题而被卡半天,其实我们不难发现,要想使题目存在节点,就得让该节点出现一条环同时,而且环最后的头和尾颜色还必须得相等。直接dfs跑环加暴力枚举即可。

// #pragma GCC optimize(3)  //O2优化开启
#include
using namespace std;
#define int long long
typedef long long ll;
typedef pair PII;
const int N=998244353;
const int MX=0x3f3f3f3f3f3f3f3f; 
int n,m;
int id;
int ue[1000005];
void icealsoheat(){
    cin>>n>>m;
    vector>ve(n+5);
    for(int i=1;i<=m;i++){
        int l,r;
        cin>>l>>r;
        ve[l].push_back(r);
        ve[r].push_back(l);
    }
    vectorc(n+5,0);
    for(int i=1;i<=n;i++)cin>>ue[i];
    bool f=0;
    id=0;
    auto dfs=[&](auto self,int x,int fa)->void{
        for(auto i:ve[x]){
            if(c[i]||ue[i]==ue[x])continue;
            c[i]=id;
            self(self,i,x);
        }
    };
    for(int i=1;i<=n;i++){
        if(c[i]==0){
            id++;
            c[i]=id;
            dfs(dfs,i,-1);
        }
        for(auto j:ve[i]){
            if(ue[i]==ue[j]&&c[i]==c[j])f=1;
        }        
        if(f)break;

    }
    // for(int i=1;i<=n;i++)cout<>_;
    while(_--){
        icealsoheat();
    }
}

C - Reversible Card Game

AC修炼计划(AtCoder Regular Contest 164)_第2张图片

通过贪心的思想,双方若想都取最优,爱丽丝尽可能把差值大的值的从大的翻到小的,而鲍勃尽可能的在爱丽丝得手之前把没翻的牌(差值尽可能大的)拿走。然后,当正面大的牌都拿完的时候,鲍勃只需跟着爱丽丝拿,爱丽丝翻一张(把大的值翻上来),鲍勃就拿一张。

// #pragma GCC optimize(3)  //O2优化开启
#include
using namespace std;
#define int long long
typedef long long ll;
typedef pair PII;
const int N=998244353;
const int MX=0x3f3f3f3f3f3f3f3f; 
int n,m;
int a[1000005];
int b[1000005];
bool c[1000005];
struct we{
    int x;
    int cha;
    bool operator <(const we &k)const{
        return k.cha>cha;
    }
};
bool cmp(we ae,we be){
    return ae.cha>n;
    priority_queueq;
    vectorve;
    priority_queueqq;
    int ans=0;
    for(int i=1;i<=n;i++){
        cin>>a[i]>>b[i];
        ans+=min(a[i],b[i]);
        if(a[i]>b[i]){
            q.push({i,abs(a[i]-b[i])});
        }
        else{
            ve.push_back({i,abs(a[i]-b[i])});
        }
    }
    int op=0;
    while(q.size()){
        we now=q.top();
        q.pop();
        if(op==0){
            op^=1;
            ve.push_back({now});
        }
        if(!q.size())break;
        now=q.top();
        q.pop();
        if(op==1){
            op^=1;
            ans+=now.cha;
        }
    }
    // cout<>_;
    while(_--){
        icealsoheat();
    }
}

D - 1D Coulomb

AC修炼计划(AtCoder Regular Contest 164)_第3张图片

一道很经典很妙的dp。

我们需要用dp迭代一下类似括号匹配的一样的结构。让+与-相互抵消。

dp[i][j]为值的和,i代表了前i个字母,j代表着+与-的差值状态。(n为+与-相等,0到n-1是-的较多,n+1到2*n是+较多)。hh[i][j]为当前方案的次数。

代码如下:

//#pragma GCC optimize(3)
#include
using namespace std;
#define int long long
typedef long long ll;
typedef pair PII;
const int N=998244353;
int n,m,k;
void icealsoheat(){
    cin>>n;
    string s;
    cin>>s;
    s=' '+s;
    vector>dp(2*n+5,vector(2*n+5,0));
    vector>hh(2*n+5,vector(2*n+5,0));
    hh[0][n]=1;
    for(int i=1;i<=2*n;i++){
        for(int j=0;j<=2*n;j++){
            if(s[i]=='+'||s[i]=='?'){
                if(j>0){
                    dp[i][j]=(dp[i][j]+dp[i-1][j-1])%N;
                    hh[i][j]=(hh[i][j]+hh[i-1][j-1])%N;
                }
                if(j<=n&&j>0){
                    int v=n-j;
                    v=v*2+1;
                    dp[i][j]=(dp[i][j]+hh[i-1][j-1]*v%N)%N;
                }
            }
            if(s[i]=='-'||s[i]=='?'){
                if(j<2*n){
                    dp[i][j]=(dp[i][j]+dp[i-1][j+1])%N;
                    hh[i][j]=(hh[i][j]+hh[i-1][j+1])%N;
                }
                if(j>=n&&j<2*n){
                    int v=j-n;
                    v=v*2+1;
                    dp[i][j]=(dp[i][j]+hh[i-1][j+1]*v%N)%N;                    
                }
            }
        }
    }
    cout<>_;
    while(_--){
        icealsoheat();
    }
}

你可能感兴趣的:(算法,c++,动态规划)