P9573 「TAOI-2」核心共振

发布时间 2023-08-22 19:38:57作者: One_JuRuo

思路

这道题最开始没发现数列必须是 \(1,2,3,\cdots,n\),然后直接交了个输出 \(n\)\(p\) 的代码。我真的好蠢啊

后面才发现这一点,于是开始思考,首先从 \(p\) 比较小的情况。

如果 \(p\)\(1\) 的话,那显然直接输出 \(1,2,3,\cdots,n\) 就好了。

如果 \(p\)\(2\) 的话,显然奇数和偶数放在一次效果最佳。

如果 \(p\)\(3\) 的话,那 \(3\) 的倍数放一次,余数是 \(1\)\(2\) 交替放在一次最好。

至此,我们便发现了一个大致解法,就是余数为 \(0\) 的应当放在一起,余数和为 \(p\) 的应当放在一起,才能最大化共振次数。

55pts 代码

#include<bits/stdc++.h>
using namespace std;
int T,n,p,t;
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&p),t=p;
		if(n==1){printf("%d\n",1);continue;}//当时没想好的时候特判的,后面懒得删了
		for(int i=0;i<p;++i)
		{
			for(int j=0;j*t+i<=n;++j)
			{
				if(!i&&!j) continue;//对于0的特殊情况
				if(i==0||t-i==i) printf("%d ",j*t+i);//余数为0和p/2的情况不需要交替输出
				else
				{
					printf("%d ",j*t+i);
					if(j*t+t-i<=n) printf("%d ",j*t+t-i);//后面一个可能会比前一个少一个,注意判断
				}
			}
			if(i!=0&&t-i!=i)--p;//重复的需要减了(绝对不是我懒得去算到底有多少次)
		}
		puts("");
	}
	return 0;
}

居然 TLE 了,想了一下,我这个第一层最多是 \(p\),第二层最多是 \(\frac{n}{p}\) 乘起来不就 \(n\) 吗?

一看数据范围,\(\sum n\) 最大也才 \(3\times10^5\) 怎么会 TLE 呢。

就在我百思不得其解的时候,突然看到样例最后一组,\(p\)\(n\) 大,所以共振次数必定是 \(0\),然后一看 \(p\) 的范围,居然有 \(10^8\),这样一看,如果每次都是 \(p\) 都比 \(n\) 大,那复杂度就是 \(O(p)\) 了,再乘以个 \(T\),超时是必然的。

所以循环的时候再加个 \(min(n+1,p)\) 就好了。

AC 代码

#include<bits/stdc++.h>
using namespace std;
int T,n,p,t;
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&p),t=p;
		if(n==1){printf("%d\n",1);continue;}
		for(int i=0;i<min(n+1,p);++i)//与上面的没什么区别,就这里改了
		{
			for(int j=0;j*t+i<=n;++j)
			{
				if(!i&&!j) continue;
				if(i==0||t-i==i) printf("%d ",j*t+i);
				else
				{
					printf("%d ",j*t+i);
					if(j*t+t-i<=n) printf("%d ",j*t+t-i);
				}
			}
			if(i!=0&&t-i!=i)--p;
		}
		puts("");
	}
	return 0;
}