Kai’blog

主博客 | 势利纷华,近之而不染者洁,不近者亦洁,君子不立危墙之下。

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;
}
posted @ 2024-02-14 16:52  Kai-G  阅读(4)  评论(0编辑  收藏  举报
Copyright © 2019-2020 拱垲. All rights reserved.