由于时间没赶上摸底,只能跟一波新增的dp摸底,感觉难度一般般,可能有段时间内没做题的缘故吧
暑训就要开始了呢
A 黑白棋
思路:一上来就是个博弈搜索
根据上一状态与这一状态必胜必败态的转换来判断先手的情况
dfs搜索所有前项状态,若均为必败态,则该状态为必胜态,否则为必败态
/*
Author:Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
int a[5][5];
int dfs(int x,int y)
{
int next[2][4]={{0,0,1,-1},{1,-1,0,0}};
int x1,y1,i,p=1;
for(i=0;i<4&&p==1;i++)
{
x1=x+next[0][i];
y1=y+next[1][i];
if(x1>=0&&y1>=0&&x1<5&&y1<5&&a[x1][y1]==0)
{
a[x1][y1]=1;
p=(dfs(x1,y1)+1)%2;
a[x1][y1]=0;
}
}
return p;
}
int main()
{
int i,j,t;
scanf("%d",&t);
while(t--)
{
for(i=0;i<5;i++)
{
for(j=0;j<5;j++)
{
scanf("%1d",&a[i][j]);
}
}
int p=0;
for(i=0;i<5&&p==0;i++)
{
for(j=0;j<5&&p==0;j++)
{
if(a[i][j]==0)
{
a[i][j]=1;
p=dfs(i,j);
a[i][j]=0;
}
}
}
if(p==0)
printf("lose\n");
else
printf("win\n");
}
return 0;
}
B The most orz man
思路:sg值打表找规律
sg值:mex函数为下一状态的sg值,则该状态sg值为最小不属于mex的非负整数
这是个很巧妙的方法,成功利用数学方式构造了必胜必败态模型,通过计算实现结果的模拟
最终发现3的整数倍为必胜态,成功ac
/*
Author:Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
/*
const int maxn = 10010;
int sg[maxn];
void getSG(int a[],int n)//a为可能走法,n为所求sg数量
{
int i,j;
int temp[maxn];//存储前项sg值,用于求mex
memset(sg,0,sizeof(sg));
for(i=0;i<n;i++)//依次求sg值
{
memset(temp,0,sizeof(temp));
for(j=0;i-a[j]>=0;j++)//j为可走步数
{
if(i<a[0])
break;
temp[sg[i-a[j]]]=1;
}
for(j=0;j<n;j++)
{
if(temp[j]==0)
{
sg[i]=j;
break;
}
}
}
}
*/
int main()
{
int n;
/*int a[maxn],t=1;
for(int i=0;i<70;i++)
{
a[i]=t;
t*=2;
if(t<0)
{
break;
}
}*/
while(scanf("%d",&n)!=EOF)
{
/*getSG(a,n);
for(int j=0;j<n;j++)
{
printf("%d %d\n",j,sg[j]);
}*/
if(n%3==0)
{
printf("No\n");
}
else
{
printf("Yes\n");
}
}
return 0;
}
D 易碎的鸟蛋
思路:典型的dp,以两个题设变量鸡蛋数n和楼层数m作为状态变量,以所求结果最少实验次数作为dp值,枚举投放鸡蛋的试验楼层
可得到两种情况,分为鸡蛋破碎和未破碎,于是一分为二
若鸡蛋破碎,则继续试验较低楼层,但可用鸡蛋数减一
若鸡蛋未破,则将上层楼层提取出来,成为研究楼高仅为上层楼层的子问题
两种情况中较高的试验次数作为该状态的dp值,枚举结果中取最低值进行转移
转移方程为dp[i][j]=min((max(dp[i-1][k-1],dp[i][j-k])+1),dp[i][j])
/*
Author:Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+10;
int dp[maxn][maxn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int j=0;j<=1000;j++)
{
dp[0][j]=0;
dp[1][j]=j;
dp[j][0]=0;
dp[j][1]=1;
}
for(int i=2;i<=n;i++)
{
for(int j=2;j<=m;j++)
{
dp[i][j]=dp[i-1][j];
for(int k=1;k<=j;k++)
{
dp[i][j]=min((max(dp[i-1][k-1],dp[i][j-k])+1),dp[i][j]);
}
}
}
printf("%d\n",dp[n][m]);
}
return 0;
}
最终摸底的结果还是可以接受的,全场第三,d题一开始总想着二分找最优状态,后来发现不足10的数据量完全可以枚举,或许利用计算机才是acm正确的姿势吧
dp专题,怎么能没有状压呢,上次的c题就是一个典型的状压
C 裁玻璃
思路:按层转移,每层的状态只与其上一层状态有关,由于每层的列数很少,完全可以考虑用二进制数存储状态,状态压缩。特殊考虑无法放玻璃的位置,对于本层将其考虑为未放置,对于下层,将其考虑为已放置。
关键对于不可能成立的情况,可以直接将其赋值为-1e9,避免其被挑选到,每次筛选出满足的最大值作为转移结果。
最后,就是注意第一层初始条件需要单独考虑,就ok了
/*
Author:Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000;
int row,n,t;
int dp[maxn][12];
bool good[12][12];
void cal(int k,int state)
{
int add = 0;
int realstate = state;
for(int i=0;i<n;i++)
{
if(!good[k][i+1])
{
if(realstate&(1<<i))
{
realstate ^= (1<<i);
}
else
{
dp[state][k] = -1e9;
return ;
}
}
}
//cout << k << "*" << state << "*****" << realstate << endl;
//cout << good[k][1] << good[k][2] << good[k][3] << good[k][4] << endl;
bool half = false;
for(int i=0;i<n;i++)
{
if(realstate&(1<<i))
{
if(half)
{
half = false;
add++;
}
else
{
half = true;
}
}
else
{
if(half)
{
dp[state][k] = -1e9;
return ;
}
}
}
if(k==1)
{
add = 0;
}
for(int s=0;s<=((1<<n)-1);s++)
{
int pos;
for(pos=0;pos<n;pos++)
{
if((realstate&(1<<pos))&&(s&(1<<pos)))
{
break;
}
}
if(pos==n&&((dp[s][k-1]+add)>dp[state][k]))
{
dp[state][k] = dp[s][k-1]+add;
}
}
return ;
}
int main()
{
//cout << (1<<10) << endl;
while(scanf("%d",&t)!=EOF)
{
while(t--)
{
scanf("%d%d",&row,&n);
memset(dp,0,sizeof(dp));
memset(good,true,sizeof(good));
for(int i=1;i<=row;i++)
{
for(int j=1;j<=n;j++)
{
int temp;
scanf("%d",&temp);
if(temp == 0)
{
good[i][j] = false;
}
}
}
for(int i=1;i<=row;i++)
{
for(int s=0;s<=((1<<n)-1);s++)
{
cal(i,s);
}
}
int maxblock = 0;
for(int s=0;s<=((1<<n)-1);s++)
{
if(dp[s][row]>maxblock)
{
maxblock = dp[s][row];
}
}
printf("%d\n",maxblock);
//cout << ((1<<3)|(1<<2)|(1<<1)|(1<<0)) <<"*"<<dp[(1<<3)|(1<<2)|(1<<1)|(1<<0)][2] << endl;
/*for(int s=0;s<=((1<<n)-1);s++)
{
if(dp[s][1]>=0)
{
cout << s << "**" << dp[s][1] << endl;
}
}*/
}
}
return 0;
}