CF1928E Modular Sequence

原题链接

p=xmody。思考发现本质是 x,x+y,x+2y,,x+k1y,p,p+y,p+2y,,p+k2y,p,p+y,p+2y,,p+k3y,即每次二操作会使 y 的系数变为 0

枚举第 i 次操作是第一次二操作,记 s1=s(i×x+y×i(i1)2+(ni)×p),也就是第一次二操作后通过若干个 y 凑出来的数,当 s1<0 或者 ys1 时不合法。

那么我们现在要使系数和为 s1y 且操作次数不大于 ni 次,所以可以用一个背包来找出凑出系数 j 的最小操作数。连续的 1 次二操作和 i1 次一操作可以获得 i(i1)2 的贡献,可知有用的 i 是根号级别的,直接背包,然后记录一下 DP 路径,最后就可以输出方案了。注意如果最少操作数小于 ni,那么要多进行几次二操作来补满。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int MAXN=2e5+10,INF=1e9+7;
int T,n,x,y,s,f[MAXN],d[MAXN];
inline bool B(int k,int s)
{
    if(s<0||s%y) return false;
    if(f[s/y]>k) return false;
    s/=y;cout<<"Yes\n";
    for(int i=1;i<=n-k;++i) cout<<x+(i-1)*y<<' ';
    for(int i=1;i<=k-f[s];++i) cout<<x%y<<' ';
    while(s)
    {
        for(int i=1;i<=d[s];++i)
            cout<<x%y+(i-1)*y<<' ';
        s-=d[s]*(d[s]-1)/2;
    }
    cout<<'\n';return true;
}
inline void work()
{
    cin>>n>>x>>y>>s;bool flag=false;
    for(int i=1;i<=n;++i)
        if(B(n-i,s-(x*i+i*(i-1)/2*y+(n-i)*(x%y))))
            {flag=true;break;}
    if(!flag) cout<<"No\n";return ;
}
signed main()
{
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    for(int i=1;i<=200000;++i) f[i]=INF;
    for(int i=1;;++i)
    {
        int cur=i*(i-1)/2;if(cur>200000) break;
        for(int j=cur;j<=200000;++j)
        {
            if(f[j-cur]+i<f[j])
                f[j]=f[j-cur]+i,d[j]=i;
        }
    }
    cin>>T;while(T--) work();
    return 0;
}
posted @   int_R  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示