Luogu2044 [NOI2012]随机数生成器
https://www.luogu.com.cn/problem/P2044
矩阵快速幂
\[X_{n+1}=aX_{n}+c\\
\begin{cases}
X_{n+1}=aX_{n}+1*c\\
c=0*X_{n}+1*c
\end{cases}
\]
但是模数有点大(\(10^{18}\)),会爆\(long\quad long\)
虽然可以__int128跑过去
#include<cstdio>
#include<iostream>
#define n 2
#define ll __int128
using namespace std;
ll m,a,c,X0,N,g;
struct mat
{
ll f[n+1][n+1];
mat operator *(mat b)
{
mat c;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
c.f[i][j]=0;
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
c.f[i][j]=(c.f[i][j]+f[i][k]*b.f[k][j])%m;
return c;
}
}zero,ans,cs,zy;
__int128 read()
{
__int128 s=0;
char c=getchar();
while (!isdigit(c))
c=getchar();
while (isdigit(c))
{
s=(s << 3)+(s << 1)+(c^48);
c=getchar();
}
return s;
}
void write(__int128 x)
{
if (x>=10)
write(x/10);
putchar(x%10+48);
}
mat ksm(mat x,ll y)
{
mat ans=zero;
while (y)
{
if (y&1)
ans=ans*x;
x=x*x;
y >>=1;
}
return ans;
}
int main()
{
for (int i=1;i<=n;i++)
zero.f[i][i]=1;
m=read(),a=read(),c=read(),X0=read(),N=read(),g=read();
cs.f[1][1]=X0,cs.f[2][1]=c;
zy.f[1][1]=a,zy.f[1][2]=1,zy.f[2][2]=1;
ans=ksm(zy,N)*cs;
write(ans.f[1][1]%g),putchar('\n');
return 0;
}
毕竟不是正解(NOI试试)
正经点,写了个高精度乘法,然后一位一位乘过去,边乘边取模,用了\(unsigned \quad long \quad long\)
#include<cstdio>
#include<iostream>
#include<cstring>
#define n 2
#define ll long long
using namespace std;
ll m,a,c,X0,N,g;
int xw,yw,xx[25],yy[25],w[45];
ll cf(ll x,ll y)//高精度
{
if (!x||!y)
return 0;
xw=0,yw=0;
while (x)
{
xw++;
xx[xw]=x%10;
x/=10;
}
while (y)
{
yw++;
yy[yw]=y%10;
y/=10;
}
memset(w,0,sizeof w);
for (int i=1;i<=xw;i++)
for (int j=1;j<=yw;j++)
w[i+j-1]+=xx[i]*yy[j];
for (int i=1;i<=42;i++)
if (w[i]>9)
{
w[i+1]+=w[i]/10;
w[i]%=10;
}
int len=0;
for (int i=42;i>=1;i--)
if (w[i])
{
len=i;
break;
}
unsigned long long ans=0;
for (int i=len;i>=1;i--)
ans=(ans*10+w[i])%m;
return ans;
}
struct mat
{
ll f[n+1][n+1];
mat operator *(mat b)
{
mat c;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
c.f[i][j]=0;
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
c.f[i][j]=(c.f[i][j]+cf(f[i][k],b.f[k][j]))%m;
return c;
}
}zero,ans,cs,zy;
ll read()
{
ll s=0;
char c=getchar();
while (!isdigit(c))
c=getchar();
while (isdigit(c))
{
s=(s << 3)+(s << 1)+(c^48);
c=getchar();
}
return s;
}
void write(ll x)
{
if (x>=10)
write(x/10);
putchar(x%10+48);
}
mat ksm(mat x,ll y)
{
mat ans=zero;
while (y)
{
if (y&1)
ans=ans*x;
x=x*x;
y >>=1;
}
return ans;
}
int main()
{
for (int i=1;i<=n;i++)
zero.f[i][i]=1;
m=read(),a=read(),c=read(),X0=read(),N=read(),g=read();
cs.f[1][1]=X0,cs.f[2][1]=c;
zy.f[1][1]=a,zy.f[1][2]=1,zy.f[2][2]=1;
ans=ksm(zy,N)*cs;
write(ans.f[1][1]%g),putchar('\n');
return 0;
}
还可以用龟速乘处理
#include<cstdio>
#include<iostream>
#define n 2
#define ll long long
using namespace std;
ll m,a,c,X0,N,g;
ll cf(ll x,ll y)//龟速乘
{
ll ans=0;
while (y)
{
if (y&1)
ans=(ans+x)%m;
x=(x << 1)%m;
y >>=1;
}
return ans;
}
struct mat
{
ll f[n+1][n+1];
mat operator *(mat b)
{
mat c;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
c.f[i][j]=0;
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
c.f[i][j]=(c.f[i][j]+cf(f[i][k],b.f[k][j]))%m;
return c;
}
}zero,ans,cs,zy;
ll read()
{
ll s=0;
char c=getchar();
while (!isdigit(c))
c=getchar();
while (isdigit(c))
{
s=(s << 3)+(s << 1)+(c^48);
c=getchar();
}
return s;
}
void write(ll x)
{
if (x>=10)
write(x/10);
putchar(x%10+48);
}
mat ksm(mat x,ll y)
{
mat ans=zero;
while (y)
{
if (y&1)
ans=ans*x;
x=x*x;
y >>=1;
}
return ans;
}
int main()
{
for (int i=1;i<=n;i++)
zero.f[i][i]=1;
m=read(),a=read(),c=read(),X0=read(),N=read(),g=read();
cs.f[1][1]=X0,cs.f[2][1]=c;
zy.f[1][1]=a,zy.f[1][2]=1,zy.f[2][2]=1;
ans=ksm(zy,N)*cs;
write(ans.f[1][1]%g),putchar('\n');
return 0;
}
实测还是高精度最快