现在的位置: 首页 > 综合 > 正文

2013 hdu 西山居复赛(1) HDU 4557 非诚勿扰 HDU 4558 剑侠情缘 HDU 4559 涂色游戏 HDU 4560

2013年08月10日 ⁄ 综合 ⁄ 共 6207字 ⁄ 字号 评论关闭

转载 http://www.cnblogs.com/kuangbin/archive/2013/05/24/3097767.html

今天的比赛。。。。。速度还是慢了。。。

无缘无故错误提交好多次。。哭了。。。。

比较简单:

A题:HDU 4557

非诚勿扰

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4557

暴力胡搞,水题:

//============================================================================
// Name        : A.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
const int MAXN=1010;
char str[MAXN][100];
int a[MAXN];
bool used[MAXN];


int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int T;
    int n;
    int top;
    scanf("%d",&T);
    int iCase=0;
    while(T--)
    {
        iCase++;
        printf("Case #%d:\n",iCase);
        scanf("%d",&n);
        char op[20];
        memset(used,false,sizeof(used));
        int num=0;
        top=0;
        while(n--)
        {
            scanf("%s",&op);
            if(op[0]=='A')
            {
                scanf("%s%d",&str[top],&a[top]);
                top++;
                num++;
                printf("%d\n",num);
            }
            else
            {
                int tmp;
                scanf("%d",&tmp);
                int k=-1;
                for(int i=0;i<top;i++)
                    if(!used[i]&&a[i]>=tmp)
                        if(k==-1||(a[i]<a[k]))
                        {
                            k=i;
                        }
                if(k==-1)printf("WAIT...\n");
                else
                {
                    printf("%s\n",str[k]);
                    used[k]=true;
                    num--;
                }
            }
        }
    }

    return 0;
}

A

B题:HDU 4558

剑侠情缘

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4558

DP

一开始状态想错了。。只要记录差值就可以的

dp[i][j][x]表示在(i,j)这个点,差值为x

转移的时候把差值取相反数就实现轮流了

dp[i][j][x]表示(i,j)出发。人和剑的能量的差值为x.可以得到的相反数

那么状态转移的时候,首先x+=这个点的值。。如果这个时候x==0表示想到了,那么dp[i][j][x]++

然后往下和往右转移。下一步是更新剑了。所以对x取相反数

//============================================================================
// Name        : B.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
const int MAXN=500;
char str[MAXN][MAXN];
const int MOD=1e9+7;
int dp[MAXN][MAXN][11];

int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int T;
    int n,m;
    scanf("%d",&T);
    int iCase=0;
    while(T--)
    {
        iCase++;
        printf("Case %d: ",iCase);
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)scanf("%s",str[i]);
        int ans=0;
        memset(dp,0,sizeof(dp));
        for(int i=n-1;i>=0;i--)
        {
            for(int j=m-1;j>=0;j--)
            {
                for(int x=0;x<11;x++)
                    {
                        int tmp=x+(str[i][j]-'0');
                        tmp=(tmp)%11;
                        int tmp2=(11-tmp)%11;
                        if(i<n-1)
                        {
                            dp[i][j][x]+=dp[i+1][j][tmp2];
                        }
                        dp[i][j][x]%=MOD;
                        if(j<m-1)dp[i][j][x]+=dp[i][j+1][tmp2];
                        dp[i][j][x]%=MOD;
                        if(tmp==0)
                        {
                            dp[i][j][x]++;
                            dp[i][j][x]%=MOD;
                        }
                        if(x==0)
                        {
                            ans+=dp[i][j][x];
                            ans%=MOD;
                        }
                    }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

B

 

C:HDU 4559

涂色游戏

博弈题:

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4559

SG函数计算。

SG函数很高深。。。

想了好久才会。

其实1*1的点sg值就是1

sg[i]表示2*i 的sg值。

sg[i]求解就是普通的SG函数了。

然后进行分段做。

分段;

//============================================================================
// Name        : C.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
const int MAXN=5000;
int sg[MAXN];
bool vis[MAXN];
int mex(int x)
{
    if(sg[x]!=-1)return sg[x];
    memset(vis,false,sizeof(vis));
    for(int i=0;x-1-i>=i;i++)
    {
        int tmp=mex(i)^mex(x-1-i)^1;
        vis[tmp]=true;
    }
    for(int i=0;x-2-i>=i;i++)
    {
        int tmp=mex(i)^mex(x-2-i);
        vis[tmp]=true;
    }
    for(int i=0;;i++)
        if(!vis[i])
        {
            sg[x]=i;
            break;
        }
    return sg[x];
}
bool g[2][MAXN];
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    memset(sg,-1,sizeof(sg));
    sg[0]=0;
    for(int i=1;i<5000;i++)
        sg[i]=mex(i);
    int T;
    scanf("%d",&T);
    int iCase=0;
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        memset(g,false,sizeof(g));
        int u,v;
        while(m--)
        {
            scanf("%d%d",&u,&v);
            u--;v--;
            g[u][v]=true;
        }
        int len=0;
        int ans=0;
        for(int i=0;i<n;i++)
        {
            if(g[0][i]||g[1][i])
            {
                ans^=sg[len];
                len=0;
                if(g[0][i]&&g[1][i])continue;
                ans^=1;
            }
            else len++;
        }
        ans^=sg[len];
        iCase++;
        if(ans)printf("Case %d: Alice\n",iCase);
        else printf("Case %d: Bob\n",iCase);
    }
    return 0;
}

C

 

D:HDU 4560

我是歌手

最大流+二分

链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4560

这个题目的建图比较常规。

N个歌手编号为1~N

M种歌曲,拆点。编号分别为N+1~N+M,N+M+1~N+2*M

源点为0,汇点为N+2*M+1  总共N+2*M+2个点。

N+i 和  N+M+i  之间连权值为K的边,作为限制。

对于i, j  如果i对j擅长,那么连边 i -> N+M+j

否则连边 i -> N+j 这样就可以限制了。

然后是二分答案。

0~(1~N)之间,连边 mid .

(N+M+1~N+2*M)与N+2*M+1之间也连边mid

然后判断mid*N和最大流是不是相当。

然后就是最大流模板题了。

//============================================================================
// Name        : D.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;

const int MAXN=1100;
int maze[MAXN][MAXN];
int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];
int flow[MAXN][MAXN];//存最大流的容量
int sap(int start,int end,int nodenum)
{
    memset(cur,0,sizeof(cur));
    memset(dis,0,sizeof(dis));
    memset(gap,0,sizeof(gap));
    memset(flow,0,sizeof(flow));
    int u=pre[start]=start,maxflow=0,aug=-1;
    gap[0]=nodenum;
    while(dis[start]<nodenum)
    {
        loop:
          for(int v=cur[u];v<nodenum;v++)
            if(maze[u][v]-flow[u][v] && dis[u]==dis[v]+1)
            {
                if(aug==-1 || aug>maze[u][v]-flow[u][v])aug=maze[u][v]-flow[u][v];
                pre[v]=u;
                u=cur[u]=v;
                if(v==end)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=start;v=u,u=pre[u])
                    {
                        flow[u][v]+=aug;
                        flow[v][u]-=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
            int mindis=nodenum-1;
            for(int v=0;v<nodenum;v++)
               if(maze[u][v]-flow[u][v]&&mindis>dis[v])
               {
                   cur[u]=v;
                   mindis=dis[v];
               }
            if((--gap[dis[u]])==0)break;
            gap[dis[u]=mindis+1]++;
            u=pre[u];
    }
    return maxflow;
}

bool used[MAXN][MAXN];

int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int T;
    int N,M,L,K;
    scanf("%d",&T);
    int iCase=0;
    while(T--)
    {
        iCase++;
        scanf("%d%d%d%d",&N,&M,&L,&K);
        memset(maze,0,sizeof(maze));
        int u,v;
        memset(used,false,sizeof(used));
        while(L--)
        {
            scanf("%d%d",&u,&v);
            used[u][v]=true;
        }
        for(int i=N+1;i<=N+M;i++)maze[i][i+M]=K;
        for(int i=1;i<=N;i++)
            for(int j=1;j<=M;j++)
            {
                if(used[i][j])
                {
                    maze[i][j+N+M]=1;
                }
                else maze[i][j+N]=1;
            }
        int ans=0;
        int l=0,r=M;
        while(l<=r)
        {
            int mid=(l+r)/2;
            for(int i=1;i<=N;i++)maze[0][i]=mid;
            for(int i=N+M+1;i<=N+2*M;i++)maze[i][N+2*M+1]=mid;
            if(sap(0,N+2*M+1,N+2*M+2)==mid*N)
            {
                ans=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        printf("Case %d: %d\n",iCase,ans);
    }


    return 0;
}

D

 

抱歉!评论已关闭.