[AH2017/HNOI2017]礼物

m很小100,一个O(nm)的复杂度

两个手环增加非负整数亮度,等于其中一个增加一个整数亮度(可以为负)

显而易见,最多增加[-m,m]个亮度

考虑O(n)枚举对齐方式,O(m)枚举差距的亮度

亮度增加的时候,维护平方和,只用维护之前的平方和,所有项的和即可

但是每次旋转,初始的对齐位置会发生改变,所以暴力可以O(N^2)

我们只关心初始的平方和

拆开,其实就要求∑ai*bj

由于旋转,所以b倍长,

对应下标差一定,求乘积

把a数组reverse,然后NTT快乐搞定

开始没有注意两个环都可以增亮,,所以只枚举了[0,m],没想到有95pts、。。。

代码:

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
#define int long long
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=100000+5;
const int mod=998244353;
const int G=3;
const int GI=332748118;
const int inf=0x3f3f3f3f;
int n,m;
ll qm(ll x,ll y){
    ll ret=1;
    while(y){
        if(y&1) ret=ret*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ret;
}
int rev[8*N];
ll a[8*N],b[8*N];
void NTT(ll *f,int n,int c){
    for(reg i=0;i<n;++i){
        if(i<rev[i]) swap(f[i],f[rev[i]]);
    }
    for(reg p=2;p<=n;p<<=1){
        ll gen;
        int len=p/2;
        if(c==1) gen=qm(G,(mod-1)/p);
        else gen=qm(GI,(mod-1)/p);
        for(reg l=0;l<n;l+=p){
            ll buf=1;
            for(reg k=l;k<l+len;++k){
                ll tmp=buf*f[k+len]%mod;
                f[k+len]=(f[k]-tmp+mod)%mod;
                f[k]=(f[k]+tmp)%mod;
                buf=buf*gen%mod;
            }
        }
    }
}
void calc(ll *f,ll *g,int n){
    NTT(f,n,1),NTT(g,n,1);
    for(reg i=0;i<n;++i) f[i]=f[i]*g[i]%mod;
    NTT(f,n,-1);
    ll inv=qm(n,mod-2);
    for(reg i=0;i<n;++i) f[i]=f[i]*inv%mod;
}
int main(){
    rd(n);rd(m);
    ll s1=0,s2=0;
    ll f1=0,f2=0;
    for(reg i=0;i<n;++i) scanf("%lld",&a[i]),s1+=a[i],f1+=a[i]*a[i];
    for(reg j=0;j<n;++j) scanf("%lld",&b[j]),s2+=b[j],f2+=b[j]*b[j];
    reverse(a,a+n);
    for(reg j=n;j<=2*n-1;++j) b[j]=b[j-n];
    int lp;
    int len=0;
    for(lp=2*n+2*n,len=1;len<lp;len<<=1);
    for(reg i=0;i<len;++i){
        rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0);
    }
//    for(reg i=0;i<len;++i) printf("%d ",a[i]);puts("");
//    for(reg i=0;i<len;++i) printf("%d ",b[i]);
    
    calc(a,b,len);// ans is in array a
//    cout<<" len "<<len<<endl;
//    for(reg i=0;i<len;++i){
//        cout<<a[i]<<" ";
//    }cout<<endl;
    
    ll ans=inf;
    for(reg i=0;i<n;++i){
        ll su=0,sf=0;
        su=s1-s2;
        sf=f1+f2-2*a[i+n];
        ans=min(ans,sf);
        for(reg j=1;j<=m;++j){
            sf+=2*su+n;
            su+=n;
            ans=min(ans,sf);
        }
        su=s1-s2;
        sf=f1+f2-2*a[i+n];
        for(reg j=1;j<=m;++j){
            sf-=2*su-n;
            su-=n;
            ans=min(ans,sf);
        }
    }
    printf("%lld",ans);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/1/10 16:53:09
*/
View Code
原文地址:https://www.cnblogs.com/Miracevin/p/10251385.html