Luogu5665 划分

https://www.luogu.com.cn/problem/P5665

\(DP\)

\(36pts\)

\(dp_{i,j}\)表示前\(i\)个数,上一段取的是以位置\(j\)结尾的最小值

\(S_i\)表示前\(i\)个数的和

\[dp_{i,j}=\min \begin{cases} {S_i}^2 \\ \min dp_{j,k}+(S_i-S_j)^2 (0 \le k < j < i,S_j-S_k \le S_i-S_j) \end{cases} \]

时间复杂度:\(O(n^3)\)

\(Code:\)

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#define N 5005
#define ll long long
using namespace std;
int n,ty;
ll a[N],dp[N][N],g[N];
int main()
{
    scanf("%d%d",&n,&ty);
    for (int i=1;i<=n;i++)
        scanf("%lld",&a[i]),g[i]=g[i-1]+a[i];
    ll mx=(ll)sqrt(4000000000000000000)+1;
    for (int i=1;i<=n;i++)
    {
        if (g[i]<=mx)
            dp[i][0]=g[i]*g[i]; else
            dp[i][0]=4000000000000000005;
        for (int j=1;j<i;j++)
        {
            dp[i][j]=4000000000000000005;
            for (int k=j-1;k>=0;k--)
                if (g[j]-g[k]>g[i]-g[j])
                    break; else
                if (g[i]-g[j]<=mx)
                    dp[i][j]=min(dp[i][j],dp[j][k]+(g[i]-g[j])*(g[i]-g[j]));
        }
    } 
    ll ans=dp[n][0];
    for (int i=1;i<n;i++)
        ans=min(ans,dp[n][i]);
    printf("%lld\n",ans); 
    return 0;
}

\(64pts\)

可以观察到,对于固定的\(i,j\),\((S_i-S_j)^2\)为定值

而对于\(dp_{j,k}\)\(k\)的范围可以二分得到,\(dp_{j,k}\)可以通过后缀\(\min\)直接取得

时间复杂度:\(O(n^2 \log n)\)

\(Code:\)

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#define N 5005
#define ll long long
#define INF 4000000000000000005
using namespace std;
int n,ty;
ll a[N],dp[N][N],mn[N][N],g[N];
int main()
{
    scanf("%d%d",&n,&ty);
    for (int i=1;i<=n;i++)
        scanf("%lld",&a[i]),g[i]=g[i-1]+a[i];
    ll mx=(ll)sqrt(INF)+1;
    for (int i=1;i<=n;i++)
    {
        if (g[i]<=mx)
            dp[i][0]=g[i]*g[i]; else
            dp[i][0]=INF;
        for (int j=1;j<i;j++)
        {
            if (g[i]-g[j]>=mx)
            {
                dp[i][j]=INF;
                continue;
            }
            int l=0,r=j-1;
            int ans=-1;
            ll del=g[i]-g[j];
            while (l<=r)
            {
                int mid=(l+r) >> 1;
                if (g[j]-g[mid]<=del)
                {
                    ans=mid;
                    r=mid-1;
                } else
                    l=mid+1;
            }
            if (ans==-1)
                dp[i][j]=INF; else
            if (mn[j][ans]+(g[i]-g[j])*(g[i]-g[j])>INF)
                dp[i][j]=INF; else
                dp[i][j]=mn[j][ans]+(g[i]-g[j])*(g[i]-g[j]);
        }
        mn[i][i-1]=dp[i][i-1];
        for (int j=i-2;j>=0;j--)
            mn[i][j]=min(mn[i][j+1],dp[i][j]);
    } 
    printf("%lld\n",mn[n][0]); 
    return 0;
}

\(88pts\)

好像没有优化的思路了

只好换一个角度思考

由于答案是一堆平方的形式,我们贪心地想,肯定要让最大的一段较小,最大的一段小了,其他的段自然也小了

所以对于每个位置,我们考虑以当前位置为末尾的段最小可以取多少,记为\(dp_i\)

注意,\(dp_i\)不具有单调性,无法二分,只好借助平衡树\(fhq\_Treap\)

因为对于每个\(dp_j\),其所要比较的是\(S_i-S_j\),值是不同的,我们可以用减法来代替比较,计算时\(split\)\(\le 0\)的那部分,取标号最大的(在平衡树节点上打标记)

时间复杂度:\(O(n \log n)\)

期望得分是\(88pts\)\(loj\)也是\(88pts\),但是洛谷跑得太慢,硬把我卡成\(64pts\),开\(O2\)\(88pts\)(也许\(fhq\_Treap\)常数太大吧\(qaq\))

\(Code(Without \quad O2):\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 500005
#define ll long long
#define mx(x,y) ((x>y)?x:y)
using namespace std;
int n,ty,x,y,z,cnt,rt;
int a[N];
ll g[N],dp[N],ans[N];
struct node
{
    int sz,ls,rs,rk,v1,v2;
    ll v,del;
}s[N];
inline int read()
{
    int s=0;
    char c=getchar();
    while (c<'0' || c>'9')
        c=getchar();
    while ('0'<=c && c<='9')
    {
        s=s*10+c-'0';
        c=getchar();
    }
    return s;
}
void write(ll x)
{
    if (x>9)
        write(x/10);
    putchar(x%10+'0');
}
inline int newnode(int x,int y)
{
    cnt++;
    s[cnt].v=x;
    s[cnt].v1=s[cnt].v2=y;
    s[cnt].sz=1;
    s[cnt].ls=0;
    s[cnt].rs=0;
    s[cnt].rk=rand();
    s[cnt].del=0;
    return cnt;
}
inline void update(int x)
{
    s[x].sz=s[s[x].ls].sz+s[s[x].rs].sz+1;
    s[x].v2=mx(s[x].v1,mx(s[s[x].ls].v2,s[s[x].rs].v2));
}
inline void push_del(int x,ll y)
{
    if (!x)
        return;
    s[x].del+=y;
    s[x].v-=y;
}
inline void push_down(int x)
{
    if (!x)
        return;
    push_del(s[x].ls,s[x].del);
    push_del(s[x].rs,s[x].del);
    s[x].del=0;
}
void split(int &x,int &y,int now,ll k)
{
    if (!now)
    {
        x=y=0;
        return;
    }
    push_down(now);
    if (s[now].v<=k)
    {
        x=now;
        split(s[now].rs,y,s[now].rs,k);
    } else
    {
        y=now;
        split(x,s[now].ls,s[now].ls,k);
    }
    update(now);
}
int merge(int x,int y)
{
    push_down(x);
    push_down(y);
    if (!x||!y)
        return x|y;
    if (s[x].rk>s[y].rk)
    {
        s[x].rs=merge(s[x].rs,y);
        update(x);
        return x;
    } else
    {
        s[y].ls=merge(x,s[y].ls);
        update(y);
        return y;
    }
}
int main()
{
    srand(233333);
    n=read(),ty=read();
    for (int i=1;i<=n;i++)
        a[i]=read(),g[i]=g[i-1]+a[i];
    rt=newnode(0,0);
    for (int i=1;i<=n;i++)
    {
        push_del(rt,a[i]);
        split(x,y,rt,0);
        int rans=s[x].v2;
        dp[i]=g[i]-g[rans];
        ans[i]=ans[rans]+dp[i]*dp[i];
        split(y,z,y,dp[i]);
        rt=merge(merge(merge(x,y),newnode(dp[i],i)),z);
    }
    write(ans[n]),putchar('\n');
    return 0;
}

一琢磨,干嘛要打减法标记啊!对于每个位置\(i\)对加上\(S_i\)再丢进\(fhq\_Treap\)不就行了!

常数爆减,不开\(O2\)稳稳\(88pts\)

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 500005
#define ll long long
#define mx(x,y) ((x>y)?x:y)
using namespace std;
int n,ty,x,y,z,cnt,rt;
int a[N];
ll g[N],dp[N],ans[N];
struct node
{
    int sz,ls,rs,rk,v1,v2;
    ll v;
}s[N];
inline int read()
{
    int s=0;
    char c=getchar();
    while (c<'0' || c>'9')
        c=getchar();
    while ('0'<=c && c<='9')
    {
        s=s*10+c-'0';
        c=getchar();
    }
    return s;
}
void write(ll x)
{
    if (x>9)
        write(x/10);
    putchar(x%10+'0');
}
inline int newnode(ll x,int y)
{
    cnt++;
    s[cnt].v=x;
    s[cnt].v1=s[cnt].v2=y;
    s[cnt].sz=1;
    s[cnt].ls=0;
    s[cnt].rs=0;
    s[cnt].rk=rand();
    return cnt;
}
inline void update(int x)
{
    s[x].sz=s[s[x].ls].sz+s[s[x].rs].sz+1;
    s[x].v2=mx(s[x].v1,mx(s[s[x].ls].v2,s[s[x].rs].v2));
}
void split(int &x,int &y,int now,ll k)
{
    if (!now)
    {
        x=y=0;
        return;
    }
    if (s[now].v<=k)
    {
        x=now;
        split(s[now].rs,y,s[now].rs,k);
    } else
    {
        y=now;
        split(x,s[now].ls,s[now].ls,k);
    }
    update(now);
}
int merge(int x,int y)
{
    if (!x||!y)
        return x|y;
    if (s[x].rk>s[y].rk)
    {
        s[x].rs=merge(s[x].rs,y);
        update(x);
        return x;
    } else
    {
        s[y].ls=merge(x,s[y].ls);
        update(y);
        return y;
    }
}
int main()
{
    srand(233333);
    n=read(),ty=read();
    for (int i=1;i<=n;i++)
        a[i]=read(),g[i]=g[i-1]+a[i];
    rt=newnode(0,0);
    for (int i=1;i<=n;i++)
    {
        split(x,y,rt,g[i]);
        int rans=s[x].v2;
        dp[i]=g[i]-g[rans];
        ans[i]=ans[rans]+dp[i]*dp[i];
        split(y,z,y,dp[i]+g[i]);
        rt=merge(merge(merge(x,y),newnode(dp[i]+g[i],i)),z);
    }
    write(ans[n]),putchar('\n');
    return 0;
}

\(100pts\)

刚才\(88pts\)的优化中,我们可以看到,只需要找到\(dp_j+S_j \le S_i\)的最大的\(j\)即可

首先,对于\(j<k,dp_j+S_j \ge dp_k+S_k\),显然\(k\)一定比\(j\)更优

然后由于\(S_i\)单调递增,假设\(i\)\(fr_i\)转移而来,那么\(fr_i\)一定是单调递增的,满足决策单调性

我们可以用单调队列来维护,\(r\)指针维护队列单调性,\(l\)指针指向当前最优决策点

然而最大数字达到\(1.6 \times 10^{33}\),需要高精度

直接用\(4\)\(10^9\)进制数来模拟高精度

卡了一点常,可以发现,我们最终的四元组\((a,b,c,d)\)中,\(a,b,c,d\)均和其他大数字直接做加法,不会爆\(long \quad long\),可以最后再取模

\(loj\)上原本最原始的代码总用时\(4721ms\),最大点\(1891ms\)(用\(C\)++ \((NOI)\)评测)

\(loj\)该代码总用时\(3986ms\),最大点\(1591ms\)(用\(C\)++ \((NOI)\)评测)

时间复杂度:\(O(\alpha n)\)\(\alpha\),一个该死的常数)

\(loj\)\(AC\),洛谷不吸\(O2\)\(TLE\)(开\(O2\)可以\(AC\)

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 40000005
#define s 1000000000
#define ll long long
#define mx(x,y) ((x>y)?x:y)
#define mn(x,y) ((x<y)?x:y)
using namespace std;
int n,ty,x,y,z,B,b1,b2,m;
int fr[N],q[N],rs[10];
ll g[N],dp[N];
inline int read()
{
    int S=0;
    char c=getchar();
    while (c<'0' || c>'9')
        c=getchar();
    while ('0'<=c && c<='9')
    {
        S=S*10+c-'0';
        c=getchar();
    }
    return S;
}
inline void pr()
{
    rs[0]=1;
    for (int i=1;i<=8;i++)
        rs[i]=rs[i-1]*10;
}
inline void write(int x)
{
    if (!x)
    {
        putchar('0');
        return;
    }
    bool flag=false;
    for (int i=8;i>=0;i--)
    {
        if (!flag && x<rs[i])
            continue; else
            flag=true;
        putchar(x/rs[i]+'0');
        x%=rs[i];
    }
}
inline void qwrite(int x)
{
    for (int i=8;i>=0;i--)
    {
        putchar(x/rs[i]+'0');
        x%=rs[i];
    }
}
int main()
{
    n=read(),ty=read();
    int mo=1 << 30;
    if (!ty)
    {
        for (int i=1;i<=n;i++)
            g[i]=g[i-1]+read();
    } else
    {
        x=read(),y=read(),z=read(),b1=read(),b2=read(),m=read();
        int prep=0,p,l,r;
        for (int i=1;i<=m;i++)
        {
            p=read(),l=read(),r=read();
            int del=r-l+1;
            for (int j=prep+1;j<=p;j++)
            {
                if (j==1)
                    B=b1; else
                if (j==2)
                    B=b2; else
                    {
                        B=((ll)x*b2+(ll)y*b1+z)%mo;
                        b1=b2;
                        b2=B;
                    }
                g[j]=g[j-1]+B%del+l;
            }
            prep=p;
        }
    }
    int l=1,r=0;
    q[++r]=0;
    for (int i=1;i<=n;i++)
    {
        while (l<r && dp[q[l+1]]+g[q[l+1]]<=g[i])
            l++;
        dp[i]=g[i]-g[q[l]];
        fr[i]=q[l];
        ll o=dp[i]+g[i];
        while (l<r && o<=dp[q[r]]+g[q[r]])
            r--;
        q[++r]=i;
    }
    int u=n;
    ll ans1=0,ans2=0,ans3=0,ans4=0;
    ll ans5=0,ans6=0,ans7=0,ans8=0,ans9=0,ans10=0;
    while (u)
    {
        ans5=dp[u]/s;
        ans6=dp[u]%s;
        ans10=ans6*ans6;
        ans9=ans10/s+((ans5*ans6) << 1);
        ans10%=s;
        ans8=ans9/s+ans5*ans5;
        ans9%=s;
        ans7=ans8/s;
        ans8%=s;
        ans1+=ans7;
        ans2+=ans8;
        ans3+=ans9;
        ans4+=ans10;
        u=fr[u];
    }
    ans3+=ans4/s;
    ans4%=s;
    ans2+=ans3/s;
    ans3%=s;
    ans1+=ans2/s;
    ans2%=s;
    pr();
    if (ans1)
        write(ans1),qwrite(ans2),qwrite(ans3),qwrite(ans4),putchar('\n'); else
    if (ans2)
        write(ans2),qwrite(ans3),qwrite(ans4),putchar('\n'); else
    if (ans3)
        write(ans3),qwrite(ans4),putchar('\n'); else
        write(ans4),putchar('\n');
    return 0;
}

继续卡,我们用\(4\)\(2^{30}\)进制数,这样我们就可以利用位运算了

最后如何把\(4\)\(2^{30}\)进制数转换回来呢?

直接高精度板子吧

\(loj\)该代码总用时\(2233ms\),最大点\(738ms\)(用\(C\)++ \((NOI)\)评测)

洛谷不开\(O2\)\(AC\)了(总用时\(5.53s\),最大点\(1.78s\)

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define N 40000005
#define ll long long
#define mx(x,y) ((x>y)?x:y)
#define mn(x,y) ((x<y)?x:y)
using namespace std;
int n,ty,x,y,z,B,b1,b2,m;
int fr[N],q[N];
ll g[N],dp[N];
inline int read()
{
    int S=0;
    char c=getchar();
    while (c<'0' || c>'9')
        c=getchar();
    while ('0'<=c && c<='9')
    {
        S=S*10+c-'0';
        c=getchar();
    }
    return S;
}
#define a hz.w
#define b kz.w
#define c kzkz.w
#define d kzzf.w
#define M 105
#define P 998244353
#define inv(x) ksm(x,P-2)
#define zero(x) (x.w[0]==1 && x.w[1]==0)
#define IT vector<int> :: iterator
using namespace std;
int rev[M];
int G[2][25];
int e[M],f[M];
int ksm(int x,int y);
void NTT(int *g,int t,int s);
struct BigNumber
{
    vector<int>w;
    void set0()
    {
        w.clear();
        w.push_back(1),w.push_back(0);
    }
    void set1()
    {
        w.clear();
        w.push_back(1),w.push_back(1);
    }
    void setNum(ll x)
    {
        if (!x)
        {
            set0();
            return;
        }
        w.clear();
        w.push_back(0);
        int g=0;
        while (x)
        {
            w.push_back(x%10);
            x/=10;
            g++;
        }
        w[0]=g;
    }
}ans,s,t;
void write(BigNumber kz)
{
    for (int i=b[0];i>=1;i--)
        putchar(b[i]+'0');
    putchar('\n');
}
bool operator < (BigNumber hz,BigNumber kz)
{
    if (a[0]!=b[0])
        return a[0]<b[0];
    for (int i=a[0];i>=1;i--)
        if (a[i]!=b[i])
            return a[i]<b[i];
    return false;
}
bool operator <= (BigNumber hz,BigNumber kz)
{
    if (a[0]!=b[0])
        return a[0]<b[0];
    for (int i=a[0];i>=1;i--)
        if (a[i]!=b[i])
            return a[i]<b[i];
    return true;
}
bool operator > (BigNumber hz,BigNumber kz)
{
    if (a[0]!=b[0])
        return a[0]>b[0];
    for (int i=a[0];i>=1;i--)
        if (a[i]!=b[i])
            return a[i]>b[i];
    return false;
}
bool operator >= (BigNumber hz,BigNumber kz)
{
    if (a[0]!=b[0])
        return a[0]>b[0];
    for (int i=a[0];i>=1;i--)
        if (a[i]!=b[i])
            return a[i]>b[i];
    return true;
}
bool operator == (BigNumber hz,BigNumber kz)
{
    if (a[0]!=b[0])
        return false;
    for (int i=a[0];i>=1;i--)
        if (a[i]!=b[i])
            return false;
    return true;
}
bool operator != (BigNumber hz,BigNumber kz)
{
    if (a[0]!=b[0])
        return true;
    for (int i=a[0];i>=1;i--)
        if (a[i]!=b[i])
            return true;
    return false;
}
BigNumber operator + (BigNumber hz,BigNumber kz)
{
    int ws=max(a[0],b[0]);
    int jw=0;
    for (int i=1;i<=ws;i++)
    {
        if (b[0]<i)
        {
            b[0]++;
            b.push_back(0);
        }
        if (a[0]>=i)
            b[i]+=a[i];
        b[i]+=jw;
        jw=b[i]/10;
        b[i]%=10;
    }
    while (jw)
    {
        b[0]++;
        b.push_back(jw%10);
        jw/=10;
    }
    return kz;
}
BigNumber operator - (BigNumber hz,BigNumber kz)
{
    int ws=max(a[0],b[0]);
    for (int i=1;i<=ws;i++)
    {
        if (b[0]<i)
            b.push_back(a[i]); else
            b[i]=a[i]-b[i];
        if (b[i]<0)
        {
            b[i]+=10;
            a[i+1]--;
        }
    }
    IT it=b.end()-1;
    while (!(*it) && ws>1)
    {
        ws--;
        b.erase(it--);
    }
    b[0]=ws;
    return kz;
}
BigNumber operator * (BigNumber hz,BigNumber kz)
{
	if (zero(hz) || zero(kz))
	{
		hz.set0();
		return hz;
	}
    int la=a[0],lb=b[0];
    int s=1,l=0;
    while (s<la+lb)
    {
        s <<=1;
        l++;
    }
    rev[0]=0;
    for (int i=1;i<s;i++)
        rev[i]=(rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
    e[0]=f[0]=0;
    for (int i=1;i<=la;i++)
        e[i-1]=a[i];
    for (int i=1;i<=lb;i++)
        f[i-1]=b[i];
    for (int i=la;i<s;i++)
        e[i]=0;
    for (int i=lb;i<s;i++)
        f[i]=0;
    NTT(e,0,s);
    NTT(f,0,s);
    for (int i=0;i<s;i++)
        e[i]=(ll)e[i]*f[i]%P;
    NTT(e,1,s);
    int invs=inv(s);
    for (int i=s;i>=1;i--)
        e[i]=(ll)e[i-1]*invs%P;
    e[0]=0;
    for (int i=1;i<=la+lb;i++)
    {
        e[i+1]+=e[i]/10;
        e[i]%=10;
    }
    a[0]=la+lb;
    while (!e[a[0]] && a[0]>1)
        a[0]--;
    for (int i=1;i<=a[0];i++)
        if (la<i)
            a.push_back(e[i]); else
            a[i]=e[i];
    return hz;
}
BigNumber operator / (BigNumber hz,BigNumber kz)
{
    BigNumber kzkz,kzzf;
    c.clear();
    c.push_back(0);
    for (int i=1;i<=a[0];i++)
        c.push_back(0);
    c[0]=a[0];
    kzzf.set0();
    for (int i=a[0];i>=1;i--)
    {
        if (!(d[0]==1 && d[1]==0))
        {
            d.push_back(0);
            for (int i=d[0];i>=1;i--)
                d[i+1]=d[i];
            d[1]=a[i];
            d[0]++;
        } else
            d[1]=a[i];
        while (kzzf>=kz)
        {
            kzzf=kzzf-kz;
            c[i]++;
        }
    }
    IT it=c.end()-1;
    while (!(*it) && c[0]>1)
    {
        c[0]--;
        c.erase(it--);
    }
    return kzkz;
}
BigNumber operator % (BigNumber hz,BigNumber kz)
{
    BigNumber kzzf;
    kzzf.set0();
    for (int i=a[0];i>=1;i--)
    {
        if (!(d[0]==1 && d[1]==0))
        {
            d.push_back(0);
            for (int i=d[0];i>=1;i--)
                d[i+1]=d[i];
            d[1]=a[i];
            d[0]++;
        } else
            d[1]=a[i];
        while (kzzf>=kz)
            kzzf=kzzf-kz;
    }
    return kzzf;
}
void operator += (BigNumber &kz,BigNumber hz)
{
    kz=kz+hz;
}
void operator -= (BigNumber &kz,BigNumber hz)
{
    kz=kz-hz;
}
void operator *= (BigNumber &kz,BigNumber hz)
{
    kz=kz*hz;
}
void operator /= (BigNumber &kz,BigNumber hz)
{
    kz=kz/hz;
}
void operator %= (BigNumber &kz,BigNumber hz)
{
    kz=kz%hz;
}
BigNumber Number_Turn_BigNumber(ll x)
{
    BigNumber kz;
    if (x==0)
    {
        kz.set0();
        return kz;
    }
    b.clear();
    b.push_back(0);
    while (x)
    {
        b[0]++;
        b.push_back(x%10);
        x/=10;
    }
    return kz;
}
ll BigNumber_Turn_Number(BigNumber kz)
{
    ll y=0;
    for (int i=b[0];i>=1;i--)
        y=y*10+b[i];
    return y;
}
void NTT(int *q,int t,int s)
{
    for (int i=0;i<s;i++)
        if (i<rev[i])
            swap(q[i],q[rev[i]]);
    for (int mid=1,o=1;mid<s;mid <<=1,o++)
        for (int j=0;j<s;j+=(mid << 1))
        {
            int g=1;
            for (int k=0;k<mid;k++,g=(ll)g*G[t][o]%P)
            {
                int x=q[j+k],y=(ll)g*q[j+k+mid]%P;
                q[j+k]=(x+y)%P;
                q[j+k+mid]=(x-y+P)%P;
            }
        }
}
int ksm(int x,int y)
{
    int ans=1;
    while (y)
    {
        if (y & 1)
            ans=(ll)ans*x%P;
        x=(ll)x*x%P;
        y >>=1;
    }
    return ans;
}
void Pre()
{
    G[0][23]=ksm(3,(P-1)/(1 << 23));
    G[1][23]=inv(G[0][23]);
    for (int i=22;i>=1;i--)
    {
        G[0][i]=(ll)G[0][i+1]*G[0][i+1]%P;
        G[1][i]=(ll)G[1][i+1]*G[1][i+1]%P;
    }
}
int main()
{
    Pre();
    n=read(),ty=read();
    int mo=1 << 30;
    int dm=mo-1;
    if (!ty)
    {
        for (int i=1;i<=n;i++)
            g[i]=g[i-1]+read();
    } else
    {
        x=read(),y=read(),z=read(),b1=read(),b2=read(),m=read();
        int prep=0,p,l,r;
        for (int i=1;i<=m;i++)
        {
            p=read(),l=read(),r=read();
            int del=r-l+1;
            for (int j=prep+1;j<=p;j++)
            {
                if (j==1)
                    B=b1; else
                if (j==2)
                    B=b2; else
                    {
                        B=((ll)x*b2+(ll)y*b1+z)%mo;
                        b1=b2;
                        b2=B;
                    }
                g[j]=g[j-1]+B%del+l;
            }
            prep=p;
        }
    }
    int l=1,r=0;
    q[++r]=0;
    for (int i=1;i<=n;i++)
    {
        while (l<r && dp[q[l+1]]+g[q[l+1]]<=g[i])
            l++;
        dp[i]=g[i]-g[q[l]];
        fr[i]=q[l];
        ll o=dp[i]+g[i];
        while (l<r && o<=dp[q[r]]+g[q[r]])
            r--;
        q[++r]=i;
    }
    int u=n;
    ll ans1=0,ans2=0,ans3=0,ans4=0;
    ll ans5=0,ans6=0,ans7=0,ans8=0,ans9=0,ans10=0;
    while (u)
    {
        ans5=dp[u] >> 30;
        ans6=dp[u] & dm;
        ans10=ans6*ans6;
        ans9=(ans10 >> 30)+((ans5*ans6) << 1);
        ans10&=dm;
        ans8=(ans9 >> 30)+ans5*ans5;
        ans9&=dm;
        ans7=ans8 >> 30;
        ans8&=dm;
        ans1+=ans7;
        ans2+=ans8;
        ans3+=ans9;
        ans4+=ans10;
        u=fr[u];
    }
    ans3+=ans4 >> 30;
    ans4&=dm;
    ans2+=ans3 >> 30;
    ans3&=dm;
    ans1+=ans2 >> 30;
    ans2&=dm;
    ans.set0();
    t.set1();
    s=Number_Turn_BigNumber(mo);
    ans+=Number_Turn_BigNumber(ans4);
    t*=s;
    ans+=t*Number_Turn_BigNumber(ans3);
    t*=s;
    ans+=t*Number_Turn_BigNumber(ans2);
    t*=s;
    ans+=t*Number_Turn_BigNumber(ans1);
    write(ans);
    return 0;
}
posted @ 2020-09-06 18:10  GK0328  阅读(219)  评论(0编辑  收藏  举报