NOI Online 3游记

游记

Day 0

打了所有的模板——发现忘记了单调队列的做法,复习了一下。

Day 0.5

睡了一个好觉。

Day 1

晴空万里,热得要命。

没有空调,只得认命。

比赛于14:30正式开始。提前5分钟开放,本蒟蒻熟悉了一下考场(换房间),然后打了一遍快速幂,之后比赛就开始了。

加油!GOGOGO!

D1T1

2分钟就切掉了,直接模拟即可。

D1T2

很显然是一道略简单的 d f s dfs (深搜)问题。

但是,要注意一下开 v i s i t e d visited 数组,表示当前节点有没有被深搜过。如果已经深搜过了,那么就不用看了;否则直接从该节点深搜下去,找到该星座的星星的数量,然后用一个数组统计一下即可。

代码比较长,比赛的时候打了30分钟,又调试了15分钟。总归心态还是不错的。

D1T3

刚刚看到这题,直发蒙。

什么鬼啊?直接用动归?怎么设计状态呢?

于是,我选择回来看D1T1与D1T2。

D1T1造了2组数据确认了一下,无误;
D1T2用并查集试了一试,两种程序对拍后无误;后来自己造了三组小数据,自己手算的与机算的一样,才回到D1T3。

为了求稳,我首先打了一个大暴力(50%都过不了)——直接枚举每张钱币被选的次数,时间复杂度直接上天。

接着,受到货币系统的启发,本蒟蒻开始打好一点的暴力。

#include <bits/stdc++.h>
using namespace std;

long long n,q,tot=0,t,maxq=0;
long long value[500005],tim[500005],question[500005],dp[500005];

struct node
{
	bool getit;
	int a[205];
}visited[500005];

inline long long read()
{
	long long s=0,w=1;
	char ch=getchar();
	
	while (ch<'0'||ch>'9')
	{
		if (ch=='-')  w=-w;
		ch=getchar();
	}
	while (ch>='0'&&ch<='9')
	{
		s=(s<<1)+(s<<3)+(ch^'0');
		ch=getchar();
	}
	return s*w;
}

signed main()
{
	cin>>n>>q;
	for (long long i=1;i<=n;i++)
	{
		value[i]=read(),tim[i]=read();
		tot+=value[i]*tim[i];
		visited[value[i]].getit=1;
		visited[value[i]].a[value[i]]=1;
	}
	for (long long i=1;i<=q;i++)
	{
		cin>>question[i];
		maxq=max(maxq,question[i]);
	}
	if (n<=10)
	{
		for (long long i=1;i<=maxq;i++)
		{
			visited[i].getit=0;
			for (long long j=1;j<=n;j++)  visited[i].a[j]=0;
		}
		for (long long i=1;i<=n;i++)
		{
			visited[value[i]].getit=1;
			visited[value[i]].a[i]=1;
		}
		for (long long i=1;i<=maxq;i++)
		{
			if (visited[i].getit==0)  continue;
			
			for (long long j=1;j<=n;j++)
			{
				for (long long k=1;k<=tim[j]-visited[i].a[j];k++)
				{
					long long now=i+k*value[j];
					if (now>maxq)  break;
					if (visited[i].a[j]+k>tim[j])  break;
					else
					{
						visited[now].getit=1;
						for (long long w=1;w<=n;w++)  visited[now].a[w]=visited[i].a[w];
						visited[now].a[j]=visited[i].a[j]+k;
					}
				}
			}
		}
	}
} 

估了一下时间复杂度,50%的数据是能过的。

同时,本蒟蒻突然发现——这不就是一个有限背包吗?!天哪,这么显然的东西这个时候才想到。

于是,果断开dp。然后与原来的程序(就是受货币系统启发的那个)对拍了一下,发现差不多;最后把两个程序合并为一个,即分段选择该用哪种方法。

然后就写出了最终的代码~

#include <bits/stdc++.h>
using namespace std;

long long n,q,tot=0,t,maxq=0;
long long value[500005],tim[500005],question[500005],dp[500005];

struct node
{
	bool getit;
	int a[205];
}visited[500005];

inline long long read()
{
	long long s=0,w=1;
	char ch=getchar();
	
	while (ch<'0'||ch>'9')
	{
		if (ch=='-')  w=-w;
		ch=getchar();
	}
	while (ch>='0'&&ch<='9')
	{
		s=(s<<1)+(s<<3)+(ch^'0');
		ch=getchar();
	}
	return s*w;
}

signed main()
{
	cin>>n>>q;
	for (long long i=1;i<=n;i++)
	{
		value[i]=read(),tim[i]=read();
		tot+=value[i]*tim[i];
		visited[value[i]].getit=1;
		visited[value[i]].a[value[i]]=1;
	}
	for (long long i=1;i<=q;i++)
	{
		cin>>question[i];
		maxq=max(maxq,question[i]);
	}
	if (n<=10)
	{
		for (long long i=1;i<=maxq;i++)
		{
			visited[i].getit=0;
			for (long long j=1;j<=n;j++)  visited[i].a[j]=0;
		}
		for (long long i=1;i<=n;i++)
		{
			visited[value[i]].getit=1;
			visited[value[i]].a[i]=1;
		}
		for (long long i=1;i<=maxq;i++)
		{
			if (visited[i].getit==0)  continue;
			
			for (long long j=1;j<=n;j++)
			{
				for (long long k=1;k<=tim[j]-visited[i].a[j];k++)
				{
					long long now=i+k*value[j];
					if (now>maxq)  break;
					if (visited[i].a[j]+k>tim[j])  break;
					else
					{
						visited[now].getit=1;
						for (long long w=1;w<=n;w++)  visited[now].a[w]=visited[i].a[w];
						visited[now].a[j]=visited[i].a[j]+k;
					}
				}
			}
		}
		for (long long i=1;i<=q;i++)
		{
			t=question[i];
			if (visited[t].getit==0)  puts("No");
			else if (visited[t].getit==1)  puts("Yes");
		}
		return 0;	
	} 
	else
	{
		dp[0]=1;
		for (long long i=1;i<=n;i++)
		{
			for (long long j=maxq;j>=value[i];j--)
			{
				if (dp[j]==1)  continue;
				
				long long flag=1;
				for (long long k=j;k>=j-tim[i]*value[i];k-=value[i])
				{
					if (dp[k]==1)
					{
						flag=0;
						break;
					}
				}
				if (flag==0)  dp[j]=1;
				else dp[j]=0;
			}
		}
		for (long long i=1;i<=q;i++)
		{
			if (dp[question[i]]==0)  cout<<"No"<<endl;
			else cout<<"Yes"<<endl;
		}
		return 0;
	}
}

后来网崩了,过了好久才提交上去。结果这时电脑坑我,突然重启+更新+胡闹,让我不得不结束了这场比赛。

内心感觉要咕咕咕。

结果

预估分数: 100+100+100=300(怎么可能)

洛谷分数: 100+100+50=250(希望就这样吧)

实际分数: ___ + ____ + _____ = ______

撒花✿✿ヽ(°▽°)ノ✿撒花

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/106322512