Luogu5665 划分
https://www.luogu.com.cn/problem/P5665
\(DP\)
\(36pts\)
\(dp_{i,j}\)表示前\(i\)个数,上一段取的是以位置\(j\)结尾的最小值
\(S_i\)表示前\(i\)个数的和
时间复杂度:\(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;
}