CF1928E Modular Sequence 题解
考虑合法的答案的构成为一个 的块加上若干个 的块。因为无论加多少次 ,对 进行一次取模就都被消去了。
我们考虑枚举 的块的长度,然后判断剩余的数的总和能否被剩余的位置拼出。这里不判断剩余位置能否拼出剩余的数的总和,因为这个很难预处理,也很难快速计算。
我们把除了第一个块的元素,每一个都减去 ,再除以 ,就变成了若干个 的块。这样的好处是,如果拼出剩余的数的总和的序列长度小于剩余的位置,就可以补入 来占位。
我们记 为拼出总和为 的序列的最小长度。我们枚举 ,表示新增一个长度为 的块,可以使用等差数列求和公式得到这个块的和,容易得到如下转移方程:
由于题目需要输出方案,所以还需要记录每次转移的前驱与新增块的长度,方便输出方案。
时间复杂度为 ,可以通过。
需要注意,有很多种情况会导致当前枚举的长度不可行,具体可以看代码。
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探