P1941-DP【绿】
题目本身只是一道有些难度的普通dp题,题解中有人说可以把这个看作是背包,我不是这么做的便没细看,感觉能把他联想为背包问题的特例的人的发散思维能力真强。不过倒也没必要,常规做即可,用二维数组即可描述状态,dp[i][j]表示只由前i个横向单位长度组成的游戏中以(i,j)结尾游戏所需的最小游戏次数
然后注意读题,别理解错题意即可,遇到大部分AC小部分WA的局面就可视化输出排错即可,比如直接反过来输出dp数组从而使得输出的样子仿若游戏画面,上是上,下是下。正着输出反而没有这个效果。
但这都不重要,重要的是发现了一个非常奇特的事情,最终输出结果的时候,写成code1就最长0.98sAC了,写成code2就有少量点1.2s+TLE了
code1
cout<<1<<endl;
cout<<ans<<endl;
code2
cout<<1<<endl<<ans<<endl;
Amazing!!!
明明这段代码这运行了一次,却足足让耗时增加了0.2s,这太不可思议了,简直不合理。
我对这个的理解是,cout输出非endl对象和输出endl对象都可以返回cout对象,但是由于输出endl而返回的cout对象如果用于输出就会大大增加耗时。
但这个说法也不是很靠谱,因为我又试了printf,不论分两行输出还是分一行输出,都TLE了
所以我怀疑,是分行输出的cout莫名其妙特别对编译器的胃口,在O2优化的过程中产生了绝妙的优化效果。
但还是不是很靠谱,毕竟就是一个cout,再慢能有多慢?0.2s?荒谬
所以这是为什么呢?简直灵异事件了属于是。
紧接着,更灵异的事情出现了!!!!
我用之前AC的代码去重复提交,结果TLE了!!!又重复提交,又AC了...拿着TLE的代码反复提交也突然就AC了?!!!
离谱
这是虽然离谱,但是我却由此得到了这个问题的答案。
答案就是:这是一次“鸡误以为太阳是被自己叫起来”的事件。输出方式是什么根本不重要,具体能不能过可能取决于洛谷评测机算力的忽上忽下,也可能取决于同一代码不同时刻O2优化有着细微不同导致效率忽上忽下。第一个情况的可能性最大,第二个情况可能性不大,毕竟是同一个编译系统,理应没什么O2优化在不同时刻的不同。
因此只不过是洛谷评测机算力忽上忽下导致的,恰好和我关于cout输出方式的假设碰巧一致了,才导致了这个荒谬的结果。
问题解决了,但还有一个重要问题,那就是我的算法不吸氧不能AC...是擦着超时的边AC的,而别人的算法比我的十数倍...怎么优化呢?明天再说
Code
#include <iostream>
#include <algorithm>
#include <cmath>
#include <map>
#pragma GCC optimize (2)
using namespace std;
struct tune{int b,t;}tu[10005];
int u[10005],d[10005],b[10005],n,m,k,x;
int dp[10002][1002];
signed main()
{
//dp[i][j]表示只由前i个横向单位长度组成的游戏中以i,j结尾游戏所需的最小游戏次数
//thus dp[i][j]= _1if i has a tune and j is alive or i hasn't a tune :
//if dp[i-1][j+d[i-1]]!=-1,dp=dp[i-1][j+d[i-1]], else if dp[i-1][j-u[i-1]]!=-1,dp=1+dp[i-1][j-u[i-1]] ,else dp=-1
//_2if i has a tune and j is die thus dp[i][j]=-1
//-1 means unattachable
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m>>k;
for(int i=0;i<=n-1;i++)
cin>>u[i]>>d[i];
for(int i=1;i<=k;i++)
{
cin>>x;
cin>>tu[x].b>>tu[x].t;//only between bottom and top can be alive
b[x]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m-1;j++)
{
if(b[i]==1&&(j<=tu[i].b||j>=tu[i].t))dp[i][j]=-1;
else
{
int tans=99999999,jj=j;
if(j+d[i-1]<=m&&dp[i-1][j+d[i-1]]!=-1)
tans=min(tans,dp[i-1][j+d[i-1]]);
for(int p=1;j-u[i-1]>=1;p++)
{
if (dp[i-1][j-u[i-1]]!=-1)
tans=min(tans,p+dp[i-1][j-u[i-1]]);
j-=u[i-1];
}
if(tans!=99999999) dp[i][jj]=tans;
else dp[i][jj]=-1;
j=jj;
}
}
int j=m;
if(b[i]==1&&(j<=tu[i].b||j>=tu[i].t))dp[i][j]=-1;
else
{
int tans=99999999,jj=j,p;
for(p=1;j-u[i-1]>=1;p++)
{
if(dp[i-1][m]!=-1)
tans=min(tans,1+dp[i-1][m]);
for(int k=j-u[i-1];k<=j-1;k++)
if(dp[i-1][k]!=-1)
tans=min(tans,p+dp[i-1][k]);
j-=u[i-1];
}
for(int k=1;k<=j-1;k++)
if(dp[i-1][k]!=-1)
tans=min(tans,p+dp[i-1][k]);
if(tans!=99999999) dp[i][jj]=tans;
else dp[i][jj]=-1;
}
}
int ans=99999999;
for(int j=1;j<=m;j++)
if(dp[n][j]!=-1)
ans=min(ans,dp[n][j]);
if(ans!=99999999)
{
cout<<1<<endl<<ans<<endl;
}
else
{
for(int i=n;i>=1;i--)
{
int tf=0;
for(int j=1;j<=m;j++)
{
if(dp[i][j]!=-1)
{
tf=1;
break;
}
}
if(tf==1)
{
ans=0;
for(int ii=1;ii<=i;ii++)
if(b[ii]==1)
ans++;
cout<<0<<endl<<ans<<endl;
break;
}
}
}
/*
cout<<endl<<endl;
for(int j=m;j>=1;j--)
{
for(int i=1;i<=n;i++)
{
printf("%4d",dp[i][j]);
}
cout<<endl;
}*/
return 0;
}