转载 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