CF1928E Modular Sequence 题解

CF1928E Modular Sequence

考虑合法的答案的构成为一个 x,x+y,x+ky 的块加上若干个 xmody,xmody+y,xmody+ky 的块。因为无论加多少次 y,对 y 进行一次取模就都被消去了。

我们考虑枚举 x,x+y,x+ky 的块的长度,然后判断剩余的数的总和能否被剩余的位置拼出。这里不判断剩余位置能否拼出剩余的数的总和,因为这个很难预处理,也很难快速计算。

我们把除了第一个块的元素,每一个都减去 xmody,再除以 y,就变成了若干个 0,1,k 的块。这样的好处是,如果拼出剩余的数的总和的序列长度小于剩余的位置,就可以补入 0 来占位。

我们记 dp[i] 为拼出总和为 i 的序列的最小长度。我们枚举 j,表示新增一个长度为 j1 的块,可以使用等差数列求和公式得到这个块的和,容易得到如下转移方程:

dp[i]=min(dp[i],dp[ij×(j1)2]+j)(j×(j1)2i)

由于题目需要输出方案,所以还需要记录每次转移的前驱与新增块的长度,方便输出方案。

时间复杂度为 O(ss+n),可以通过。

需要注意,有很多种情况会导致当前枚举的长度不可行,具体可以看代码。

#include <bits/stdc++.h>
using namespace std;
long long t,n,x,y,s,f[300000],pr[300000],pz[300000],a[300000];
int main()
{
	scanf("%lld",&t);
	while(t--)
	   {
	   	bool flag=1;
	   	scanf("%lld%lld%lld%lld",&n,&x,&y,&s);
	   	for(int i=0;i<=s;i++)f[i]=1e10,pr[i]=0,pz[i]=0;
	   	f[0]=0;
	   	for(int i=1;i<=s;i++)
	   	    for(int j=2;j*(j-1)/2<=i;j++)
	   	        if(f[i-j*(j-1)/2]+j<f[i])f[i]=f[i-j*(j-1)/2]+j,pr[i]=i-j*(j-1)/2,pz[i]=j;
		for(int i=1;i<=n;i++)
	   	    {
	   	    long long ns=s-i*x-i*(i-1)*y/2;
			if(ns<0)break;
			a[1]=x;
			for(int j=2;j<=i;j++)a[j]=a[j-1]+y;
			ns-=(n-i)*(x%y);
			if(ns<0||ns%y!=0)continue;
			ns/=y;
			if(f[ns]>n-i)continue;
			flag=0;
			for(int j=i+1;j<=n-f[ns];j++)a[j]=x%y;
			long long now=n-f[ns]+1;
			while(ns)
			   {
			   	for(long long j=0;j<pz[ns];j++)a[now+j]=x%y+j*y;
			   	now+=pz[ns];
			   	ns=pr[ns];
			   }
			break;	
			}
		if(flag)printf("NO\n");
		else
		   {
		   	printf("YES\n");
		   	for(int i=1;i<=n;i++)printf("%lld ",a[i]);
		   	printf("\n");
		   }
	   }
	return 0;
}
posted @   w9095  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示