CF1728D

Posted Willette

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1728D相关的知识,希望对你有一定的参考价值。

博弈论dp模板题

首先我们可以先确定dp状态 dp[round][L][R][0/1]表示第round轮,现在字符串为[L~R],上一轮的人取了左边还是右边

然后发现round是可以由字符串L~R确定而来的,因为每一轮只删除一个数,因此可以优化round这维

我们令dp[L][R][0/1]=1为 Alice 赢,dp[L][R][0/1]=0为平局,dp[L][R][0/1]=-1为Bob胜利

对于Alice是先手,所以我们只需要ans尽量大即可:

    if(round&1) //A的轮次
        ans=max(dfs(L+1,R,0),dfs(L,R-1,1));

对于Bob是后手,所以每次都要都还要考虑 Alice 选了啥:

其实也就四种情况:

1.Alice选了L-1,Bob选了L

2.Alice选了L-1,Bob选了R

3.Alice选了R+1,Bob选了L

4.Alice选了R+1,Bob选了R

 然后让ans尽可能小就行了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pb push_back   
#define popb pop_back  
#define fi first
#define se second
#define popcount __builtin_popcount
const int N=2010;
//const int M=;
const int inf=1e9;
//const ll INF=1e18;
int T,n,dp[N][N][2];
char s[N];
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^48);ch=getchar();
    return x*f;

int dfs(int L,int R,int op)

    int round=n-(R-L+1)+1;
    if(dp[L][R][op]!=inf) return dp[L][R][op];
    int ans;
    if(round&1) //A的轮次
        ans=max(dfs(L+1,R,0),dfs(L,R-1,1));
    else //B的轮次 
    
        ans=inf;
        if(op==0) // A选了L-1的位置 
        
            // B选了L的位置
            if(dfs(L+1,R,0)==1) ans=min(ans,1);
            else if(dfs(L+1,R,0)==-1) ans=min(ans,-1);
            else 
            
                if(s[L-1]==s[L]) ans=min(ans,0);
                if(s[L-1]>s[L]) ans=min(ans,1);
                if(s[L-1]<s[L]) ans=min(ans,-1);
            
            // B选了R的位置 
            if(dfs(L,R-1,1)==1) ans=min(ans,1);
            else if(dfs(L,R-1,1)==-1) ans=min(ans,-1);
            else 
            
                if(s[L-1]==s[R]) ans=min(ans,0);
                if(s[L-1]>s[R]) ans=min(ans,1);
                if(s[L-1]<s[R]) ans=min(ans,-1);
            
          
        else // A选了 R+1 的位置
        
            // B选了L的位置
            if(dfs(L+1,R,0)==1) ans=min(ans,1);
            else if(dfs(L+1,R,0)==-1) ans=min(ans,-1);
            else 
            
                if(s[R+1]==s[L]) ans=min(ans,0);
                if(s[R+1]>s[L]) ans=min(ans,1);
                if(s[R+1]<s[L]) ans=min(ans,-1);
            
            // B选了R的位置 
            if(dfs(L,R-1,1)==1) ans=min(ans,1);
            else if(dfs(L,R-1,1)==-1) ans=min(ans,-1);
            else 
            
                if(s[R+1]==s[R]) ans=min(ans,0);
                if(s[R+1]>s[R]) ans=min(ans,1);
                if(s[R+1]<s[R]) ans=min(ans,-1);
                    
        
        
    return dp[L][R][op]=ans;
 
int main()

//    freopen("","r",stdin);
//    freopen("","w",stdout);
//    ios::sync_with_stdio(0);
//    cin.tie(0);
    T=read();
    while(T--)
    
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++)
                dp[i][j][0]=dp[i][j][1]=inf;
        int op=dfs(1,n,0);
        if(op==1) puts("Alice");
        else if(op==0) puts("Draw");
        else if(op==-1) puts("Bob");
    
    return 0;

 

 

 

IndiaHacks 2016 - Online Edition (CF) . D

这题思路很简单,二分m,求最大流是否大于等于x。

但是比赛过程中大部分的代码都被hack了。。。

精度问题,和流量可能超int

关于精度问题,这题真是提醒的到位,如果是先用二分将精度控制在10^-8左右,最后乘一个10^4,精度只能在10-4,而二分控制精度在10^-11很容易死循环(因为double 保存15-16位有效数字,结果可能为10^6级,精确到10-11,double做不到)

所以这题二分可以不写成while(d-b>eps),而直接规定二分的次数,设置成100次,基本可以保证14-15位有效数字都正确了,这时再乘10^4还是能够达到题目中要求的10^-6的精度。

还有一种处理精度的方法:

直接定义上下界就为输出的最后结果,在判断的过程中除以x,最后输出也能满足要求。

第一种精度处理方式:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include <iostream>
using namespace std;
#define eps 1e-11
#define N 55
#define M 500500
#define INF 0x3fffff



struct node1
{
    long long to,w,next;
}edge[M];

long long sn,sm,sx;
long long pre[10*N];
long long g[N][N];
long long gap[10*N],lv[10*N];
long long k,c,m;
long long cnt;
long long n,nn;
long long s,t;
long long ans;
long long sum;


void add_edge(long long u,long long v,long long w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=pre[u];
    pre[u]=cnt++;
}

long long gdfs(long long k,long long w)
{
    if(k==t) return w;
    long long f=0;
    long long mi=nn-1;
    for(long long p=pre[k];p!=-1;p=edge[p].next)
    {
        long long v=edge[p].to,tw=edge[p].w;
        if(tw!=0)
        {
            if(lv[k]==lv[v]+1)
            {
                long long tmp=gdfs(v,min(tw,w-f));
                f+=tmp;
                edge[p].w-=tmp;
                edge[p^1].w+=tmp;
                if(f==w||lv[s]==nn) break;
            }
            if(lv[v]<mi) mi=lv[v];
        }
    }
    if(f==0)
    {
        gap[lv[k]]--;
        if( gap[ lv[k] ]==0 )
        {
            lv[s]=nn;
        }
        lv[k]=mi+1;
        gap[lv[k]]++;
    }
    return f;
}

long long sap()
{
    memset(lv,0,sizeof(lv));
    memset(gap,0,sizeof(gap));
    gap[0]=nn;
    while(lv[s]<nn)
    {
        sum+=gdfs(s,INF);
    }
    return sum;
}

long long a[505],b[505],kk[505];

long long check(double mid)
{
    sum=0;
    //mid/=sx;
    memset(pre,-1,sizeof(pre));
    cnt=0;
    
    for(long long i=0;i<sm;i++)
    {
        add_edge(a[i],b[i],(long long)(kk[i]/mid+eps));
        add_edge(b[i],a[i],0);
    }
    if(sap()>=sx)
    {
        return 1;
    }
    else return 0;
}



int main()
{
    cin>>sn>>sm>>sx;
    for(long long i=0;i<sm;i++)
    {
        cin>>a[i]>>b[i]>>kk[i];
    }
    
    s=1;
    t=sn;
    nn=t+1;
    
    //这个精度问题还是很坑。。。
    double b=0,d=10000000.0;
    //好坑的东西! 我就操!
    int time=160;
    while(time--)//这里精度太小,竟然会死循环。。。
    {
        double mid=(b+d)/2;
        if( check(mid)==1 )
        {
            b = mid;
        }
        else
        {
            d = mid;
        }
    }
    printf("%.10lf",b*sx);
    return 0;
}

 

第二种精度处理方式:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include <iostream>
using namespace std;
#define eps 1e-11
#define N 55
#define M 500500
#define INF 0x3fffff



struct node1
{
    long long to,w,next;
}edge[M];

long long sn,sm,sx;
long long pre[10*N];
long long g[N][N];
long long gap[10*N],lv[10*N];
long long k,c,m;
long long cnt;
long long n,nn;
long long s,t;
long long ans;
long long sum;


void add_edge(long long u,long long v,long long w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=pre[u];
    pre[u]=cnt++;
}

long long gdfs(long long k,long long w)
{
    if(k==t) return w;
    long long f=0;
    long long mi=nn-1;
    for(long long p=pre[k];p!=-1;p=edge[p].next)
    {
        long long v=edge[p].to,tw=edge[p].w;
        if(tw!=0)
        {
            if(lv[k]==lv[v]+1)
            {
                long long tmp=gdfs(v,min(tw,w-f));
                f+=tmp;
                edge[p].w-=tmp;
                edge[p^1].w+=tmp;
                if(f==w||lv[s]==nn) break;
            }
            if(lv[v]<mi) mi=lv[v];
        }
    }
    if(f==0)
    {
        gap[lv[k]]--;
        if( gap[ lv[k] ]==0 )
        {
            lv[s]=nn;
        }
        lv[k]=mi+1;
        gap[lv[k]]++;
    }
    return f;
}

long long sap()
{
    memset(lv,0,sizeof(lv));
    memset(gap,0,sizeof(gap));
    gap[0]=nn;
    while(lv[s]<nn)
    {
        sum+=gdfs(s,INF);
    }
    return sum;
}

long long a[505],b[505],kk[505];

long long check(long double mid)
{
    sum=0;
    mid/=sx;
    memset(pre,-1,sizeof(pre));
    cnt=0;
    
    for(long long i=0;i<sm;i++)
    {
        add_edge(a[i],b[i],(long long)(kk[i]/mid+eps));
        add_edge(b[i],a[i],0);
    }
    if(sap()>=sx)
    {
        return 1;
    }
    else return 0;
}



int main()
{
    cin>>sn>>sm>>sx;
    for(long long i=0;i<sm;i++)
    {
        cin>>a[i]>>b[i]>>kk[i];
    }
    
    s=1;
    t=sn;
    nn=t+1;
    
    //这个精度问题还是很坑。。。
    long double b=0,d=1000000000.0;
    //好坑的东西! 我就操!
    while(d-b > 1e-13)//这里精度太小,竟然会死循环。。。
    {
        long double mid=(b+d)/2;
        if( check(mid)==1 )
        {
            b = mid;
        }
        else
        {
            d = mid;
        }
    }
    printf("%.20Lf",b);
    return 0;
}

以上是关于CF1728D的主要内容,如果未能解决你的问题,请参考以下文章

CF 爆发者

[CF930E]/[CF944G]Coins Exhibition

CF怎么改名

dp专题

Codeforces | CF1028C Rectangles

Codeforces 刷题记录