由于时间没赶上摸底,只能跟一波新增的dp摸底,感觉难度一般般,可能有段时间内没做题的缘故吧
暑训就要开始了呢
思路:一上来就是个博弈搜索
根据上一状态与这一状态必胜必败态的转换来判断先手的情况
dfs搜索所有前项状态,若均为必败态,则该状态为必胜态,否则为必败态
/*
Author:Owen_Q
*/
#include
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;
}
思路:sg值打表找规律
sg值:mex函数为下一状态的sg值,则该状态sg值为最小不属于mex的非负整数
这是个很巧妙的方法,成功利用数学方式构造了必胜必败态模型,通过计算实现结果的模拟
最终发现3的整数倍为必胜态,成功ac
/*
Author:Owen_Q
*/
#include
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=0;j++)//j为可走步数
{
if(i
思路:典型的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
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题就是一个典型的状压
思路:按层转移,每层的状态只与其上一层状态有关,由于每层的列数很少,完全可以考虑用二进制数存储状态,状态压缩。特殊考虑无法放玻璃的位置,对于本层将其考虑为未放置,对于下层,将其考虑为已放置。
关键对于不可能成立的情况,可以直接将其赋值为-1e9,避免其被挑选到,每次筛选出满足的最大值作为转移结果。
最后,就是注意第一层初始条件需要单独考虑,就ok了
/*
Author:Owen_Q
*/
#include
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;idp[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<maxblock)
{
maxblock = dp[s][row];
}
}
printf("%d\n",maxblock);
//cout << ((1<<3)|(1<<2)|(1<<1)|(1<<0)) <<"*"<=0)
{
cout << s << "**" << dp[s][1] << endl;
}
}*/
}
}
return 0;
}