这次比赛题有点难。。我在谷大哥的帮助下把第一题A了。。斌哥在自己的努力下把第二题A了。。于是我们拿到了。。Rank 58 。。。。。。有点夸张啊。。。我最后看了看。。一共才180个人A出来题了。。。难道其他120个名额要分给那些疯狂刷wa的人??不叨叨了看题。。。
第一题:威威猫系列故事——吃鸡腿
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4525
题解:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int T, Case = 0;
scanf("%d", &T);
while (T--)
{
Case++;
int n, k1, k2;
__int64 k;
__int64 sum = 0, sum1 = 0;
scanf("%d %d %d %I64d", &n, &k1, &k2, &k);
int i;
__int64 tmp;
for (i=0; i<n; i++)
{
scanf("%I64d", &tmp);
sum += tmp;
}
printf("Case #%d: ", Case);
sum1 = sum;
for(i=0;;i++)
{
if(sum1 > k)
{
printf("%d\n",i);
break;
}
sum = sum1;
sum1 = sum*(k1+k2);
if((sum >0 &&(k1+k2)>0 && sum1 <0))
{
printf("%d\n",i+1);
break;
}
if((sum <0 &&(k1+k2)<0 && sum1 <0))
{
printf("%d\n",i+1);
break;
}
if(i>100000)
{
printf("inf\n");
break;
}
}
}
return 0;
}
第二题:威威猫系列故事——拼车记
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4526
题解:一下是斌哥AC代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 110;
int dp[maxn][maxn];
int n, k, d, s;
int cas;
int t[maxn], z[maxn];
int main(void)
{
// freopen("f:\\code\\file\\data.txt", "r", stdin);
scanf("%d", &cas);
while(cas --)
{
scanf("%d%d%d%d", &n, &k, &d, &s);
t[0] = 0;
for(int i = 1; i <= k; i ++)
scanf("%d%d", &t[i], &z[i]);
for(int i = 0; i < maxn; i ++)
dp[i][0] = 0;
for(int i = 0; i < maxn; i ++)
{
for(int j = 1; j < maxn; j ++)
{
dp[i][j] = inf;
}
}
for(int i = 1; i <= k; i ++)
{
for(int j = 1; j <= n; j ++)
{
dp[i][j] = dp[i - 1][j];
for(int k = 1; k <= z[i]; k ++)if(j - k >= 0)
{
dp[i][j] = min(dp[i - 1][j - k] + k * t[i] + d, dp[i][j]);
}
}
}
if(dp[k][n] == inf)
printf("impossible\n");
else
printf("%d\n", dp[k][n]);
}
return 0;
}
第三题:小明系列故事——玩转十滴水
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4527
题解:(转自大牛:http://blog.csdn.net/dyx404514/article/details/8720661)
思路:模拟题,要注意两个水珠同时到达一个4级水珠的情况,我用广搜过的,反正就是根据题意模拟,没什么好说的。代码如下:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
using namespace std;
int bo[7][7];
int dir[4][2]={1,0,0,1,-1,0,0,-1};
int vis[7][7];
int check(int x,int y)
{
if(x<1||y<1||x>6||y>6)
return 0;
return 1;
}
void solve(int x,int y)
{
queue<int> q;
bo[x][y]++;
if(bo[x][y]>4)
{
vis[x][y]=0;
q.push(x);
q.push(y);
q.push(0);//时间
q.push(-1);//方向
}
int i;
while(!q.empty())
{
int xx=q.front();q.pop();
int yy=q.front();q.pop();
int tt=q.front();q.pop();
int d=q.front();q.pop();
if(d==-1)
bo[xx][yy]=0;
for(i=0;i<4;i++)
{
if(d!=-1&&d!=i)
continue;
int x1=xx+dir[i][0],y1=yy+dir[i][1];
if(check(x1,y1))
{
if(bo[x1][y1]==0)
{
q.push(x1);q.push(y1);q.push(tt+1);q.push(i);
}
else if(bo[x1][y1]<4)
{
bo[x1][y1]++;
}
else if(bo[x1][y1]==4)
{
bo[x1][y1]++;
vis[x1][y1]=tt+1;
q.push(x1);q.push(y1);q.push(tt+1);q.push(-1);
}
else
{
if(tt+1<=vis[x1][y1])
bo[x1][y1]++;
else
{
q.push(x1);q.push(y1);q.push(tt+1);q.push(i);
}
}
}
}
}
}
int main()
{
//freopen("dd.txt","r",stdin);
while(scanf("%d",&bo[1][1])!=EOF)
{
int i,j,n,x,y;
for(i=1;i<=6;i++)
{
for(j=1;j<=6;j++)
{
if(i==1&&j==1)
continue;
scanf("%d",&bo[i][j]);
}
}
scanf("%d",&n);
while(n--)
{
scanf("%d%d",&x,&y);
memset(vis,-1,sizeof(vis));
solve(x,y);
}
for(i=1;i<=6;i++)
{
for(j=1;j<=6;j++)
{
if(j!=6)
printf("%d ",bo[i][j]);
else
printf("%d",bo[i][j]);
}
printf("\n");
}
printf("\n");
}
return 0;
}
第四题:小明系列故事——捉迷藏
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4528
题解:(转自大牛:http://blog.csdn.net/dyx404514/article/details/8720661)
:搜索题,明显的宽度搜索,设dist[x][y][0]表示当前没看到大明和二明到达(x,y)时的最早时间,dp[x][y][1]表示看到大明没看到二明的最早时间,dp[x][y][2]表示看到二明而没看到大明的最早时间。我们首先预处理一下能看到大明和能看到二明的位置,然后就搜就是了。这里要注意的是我们不能穿过一个人,也就是我们要把大明和二明当做障碍物,具体看样例3。代码如下:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#define maxn 110
#define inf 2100000000
using namespace std;
int dir[4][2]={1,0,0,1,-1,0,0,-1};
int n,m;
char bo[maxn][maxn];
int check(int x,int y)
{
if(x<1||y<1||x>n||y>m||bo[x][y]!='.')
return 0;
return 1;
}
int see[2][maxn][maxn];
int dist[maxn][maxn][3];
void init(int x,int y,int t)
{
int i;
for(i=0;i<4;i++)
{
int xx=x+dir[i][0],yy=y+dir[i][1];
while(check(xx,yy))
{
see[t][xx][yy]=1;
xx+=dir[i][0];
yy+=dir[i][1];
}
}
}
int bfs(int x,int y)
{
queue<int> q;
dist[x][y][0]=0;
int t,i;
if(see[0][x][y]&&see[1][x][y])
return 0;
q.push(x);
q.push(y);
q.push(0);
while(!q.empty())
{
int xx=q.front();q.pop();
int yy=q.front();q.pop();
int tt=q.front();q.pop();
int len=dist[xx][yy][tt];
//printf("%d %d\n",xx,yy);
if(see[0][xx][yy])
{
if(tt==2)
return len;
tt=1;
}
if(see[1][xx][yy])
{
if(tt==1)
return len;
tt=2;
}
for(i=0;i<4;i++)
{
int x1=xx+dir[i][0],y1=yy+dir[i][1];
if(check(x1,y1)&&dist[x1][y1][tt]==-1)
{
dist[x1][y1][tt]=len+1;
q.push(x1);
q.push(y1);
q.push(tt);
}
}
}
return inf;
}
int main()
{
//freopen("dd.txt","r",stdin);
int ncase,time=0;
scanf("%d",&ncase);
while(ncase--)
{
printf("Case %d:\n",++time);
int t,i,j;
scanf("%d%d%d",&n,&m,&t);
for(i=1;i<=n;i++)
scanf("%s",bo[i]+1);
int sx,sy,x1,x2,y1,y2;
memset(see,0,sizeof(see));
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(bo[i][j]=='D')
x1=i,y1=j;
if(bo[i][j]=='E')
x2=i,y2=j;
if(bo[i][j]=='S')
{
bo[i][j]='.';
sx=i,sy=j;
}
}
}
memset(dist,-1,sizeof(dist));
init(x1,y1,0);
init(x2,y2,1);
//printf("f");
int ans=bfs(sx,sy);
if(ans>t)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}
第五题:郑厂长系列故事——N骑士问题
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4529
题解:(转自大牛:http://hi.baidu.com/chenwenwen0210/item/6bcc70fc605fa4e4a835a28c)
解题报告:
一看这数据范围就想到了状态压缩DP,由于马的攻击范围最多是上下2行。
所以我们只要管好前面两行的就行了,
dp[i][j][p][q]
表示第i行放马的状态是q,第i-1行的状态是p,前i行放马的个数是j个的种数。
推i+1行的时候枚举第i+1行放马的状态,进行转移。
总的复杂度无法估计,理论上是(1<<8)*(1<<8)*(1<<8)*n*8
这里需要一些剪枝,不然是通不过的。加了很多的非法判断。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<list>
using namespace std;
typedef __int64 lld;
const int MAX=10;
const int INF=1000000000;
const double EPS=1.0e-8;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int dblcmp(double x)
{
if(fabs(x)<EPS)return 0;
return x<0?-1:1;
}
int a[MAX];
lld dp[2][11][1<<8][1<<8];
char s[MAX];
bool ok1[1<<8][1<<8];
bool ok2[1<<8][1<<8];
bool judge(int a,int b,int d)
{
int i;
int x,y;
for(i=0;i+d-1<8;i++)
{
x=1<<i;
y=1<<i<<d;
if((x&a)&&(y&b))return false;
if((x&b)&&(y&a))return false;
}
return true;
}
int cnt[1<<8];
int count(int n)
{
int ret=0;
while(n)
{
ret+=n&1;
n>>=1;
}
return ret;
}
int main(){
int n=6;
int i,j;
int k;
int T;
int CS=1;
for(i=0;i<(1<<8);i++)
{
for(j=0;j<(1<<8);j++)
{
ok1[i][j]=judge(i,j,1);
ok2[i][j]=judge(i,j,2);
}
}
for(i=0;i<(1<<8);i++)
{
cnt[i]=count(i);
// printf("cnt[%d]=%d\n",i,cnt[i]);
}
//printf("%d\n",1<<8);
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=0;i<8;i++)
{
scanf("%s",s);
a[i]=0;
for(j=0;j<8;j++)
{
a[i]*=2;
if(s[j]=='*')a[i]++;
}
// printf("a[%d]=%d\n",i,a[i]);
}
memset(dp,0,sizeof(dp));
int xx=0;
for(i=0;i<(1<<8);i++)
{
if(i&a[0])continue;
if(cnt[i]>n)continue;
dp[0][cnt[i]][0][i]++;
xx++;
//printf("i=%d\n",i);
}
// printf("xx=%d\n",xx);
int tag=0;
for(i=1;i<8;i++)
{
tag=i&1;
for(xx=0;xx<=n;xx++)
{
for(j=0;j<(1<<8);j++)
{
for(k=0;k<(1<<8);k++)
{
dp[tag][xx][j][k]=0;
}
}
}
for(j=0;j<(1<<8);j++)
{
if(i-2>=0&&(j&a[i-2]))continue;
for(k=0;k<(1<<8);k++)
{
if(k&a[i-1])continue;
if(cnt[j]+cnt[k]>n)continue;
if(!ok2[j][k])continue;
int tt;
for(tt=cnt[j]+cnt[k];tt<=n;tt++)
{
if(dp[1-tag][tt][j][k]==0)continue;
for(int z=0;z<(1<<8);z++)
{
if(cnt[z]+tt>n)continue;
if(z&a[i])continue;
if(!ok2[z][k]||!ok1[z][j])continue;
dp[tag][tt+cnt[z]][k][z]+=dp[1-tag][tt][j][k];
}
}
}
}
}
lld ans=0;
for(i=0;i<(1<<8);i++)
{
for(j=0;j<(1<<8);j++)
{
//if(dp[tag][n][i][j]>0)printf("%d %d\n",i,j);
ans+=dp[tag][n][i][j];
}
}
printf("%I64d\n",ans);
}
return 0;
}
/*
2
1
*.......
....*...
.......*
.....*..
..*.....
......*.
.*......
...*....
2
1
........
........
........
........
........
........
........
........
2
1
*******.
********
********
********
********
********
********
********
*/