题解 点点的计算
发现 \(T(i, j)=i\times\binom{i}{j}\)
于是变成了一行杨辉三角的前 \(k\) 个的 lcm
\(n^2\) 的话可以将每个组合数质因数分解来处理
然后 \(n\) 变大的话
通过拆式子可以证明等价于求 \(\operatorname{lcm}(n-k+1,\cdots ,n)\)
线段树从 1 到 n 每次加入 i ,使得后 \(k\) 个数的乘积等于后 \(k\) 个数的 lcm
对当前数分解质因数,因为 lcm 实际上是对每个质因子的指数取 max
于是删除这个质因子在前面的贡献,加到当前位置即可
强制在线的话改成主席树就好
复杂度 \(O(n\log n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long
#define fir first
#define sec second
#define pb push_back
// #define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int q, n1, k1;
int a, b, Mod, c[N], d[N];
ll ans, C[1010][1010];
const ll mod=1e9+7;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}
inline ll inv(ll a) {return qpow(a, mod-2);}
namespace force{
ll query(int n, int k) {
if (k==1) return n;
ll ans=1;
for (int i=2; i<=k; ++i) ans=ans*C[n][i]%mod*inv(__gcd(ans, C[n][i]))%mod;
return ans*n%mod;
}
}
namespace task{
bool npri[N];
pair<int, int> sta[N];
vector<pair<int, int>> div[N];
int pri[N], low[N], lowp[N], lowc[N], pcnt, top, now;
int rot[N], lson[N*220], rson[N*220], tot;
ll dat[N*220];
#define ls(p) lson[p]
#define rs(p) rson[p]
#define dat(p) dat[p]
#define pushup(p) dat(p)=dat(ls(p))*dat(rs(p))%mod
void upd(int& p1, int p2, int tl, int tr, int pos, ll val) {
dat(p1=++tot)=1;
if (tl==tr) {dat(p1)=dat(p2)*val%mod; return ;}
int mid=(tl+tr)>>1;
if (pos<=mid) upd(ls(p1), ls(p2), tl, mid, pos, val), rs(p1)=rs(p2);
else upd(rs(p1), rs(p2), mid+1, tr, pos, val), ls(p1)=ls(p2);
pushup(p1);
}
ll query(int p, int tl, int tr, int ql, int qr) {
if (!p) return 1;
if (ql<=tl&&qr>=tr) return dat(p);
int mid=(tl+tr)>>1; ll ans=1;
if (ql<=mid) ans=ans*query(ls(p), tl, mid, ql, qr)%mod;
if (qr>mid) ans=ans*query(rs(p), mid+1, tr, ql, qr)%mod;
return ans;
}
void divide(int n) {top=0; for (int t=n; t>1; t/=lowp[t]) sta[++top]={low[t], lowc[t]};}
void init() {
dat[0]=1;
for (int i=2; i<N; ++i) {
if (!npri[i]) pri[++pcnt]=low[i]=lowp[i]=i, lowc[i]=1;
for (int j=1,x; j<=pcnt&&i*pri[j]<N; ++j) {
npri[x=i*pri[j]]=1;
if (i%pri[j]==0) {
low[x]=pri[j];
lowp[x]=lowp[i]*pri[j];
lowc[x]=lowc[i]+1;
break;
}
else low[x]=lowp[x]=pri[j], lowc[x]=1;
}
}
for (int i=1; i<=100000; ++i) {
// cout<<"i: "<<i<<endl;
divide(i);
// cout<<"sta: "; for (int j=1; j<=top; ++j) cout<<sta[j].fir<<','<<sta[j].sec<<' '; cout<<endl;
for (int j=1; j<=top; ++j) {
int tem=sta[j].sec;
while (div[sta[j].fir].size() && sta[j].sec) {
int t=min(div[sta[j].fir].back().sec, sta[j].sec);
++now; upd(now, now-1, 1, 100000, div[sta[j].fir].back().fir, inv(qpow(sta[j].fir, t)));
div[sta[j].fir][div[sta[j].fir].size()-1].sec-=t; sta[j].sec-=t;
if (!div[sta[j].fir].back().sec) div[sta[j].fir].pop_back();
}
div[sta[j].fir].pb({i, tem});
}
// cout<<"div: "; for (int j=1; j<=10; ++j) cout<<div[j].fir<<','<<div[j].sec<<' '; cout<<endl;
++now, upd(now, now-1, 1, 100000, i, i);
rot[i]=now;
}
}
ll solve(int n, int k) {return query(rot[n], 1, 100000, n-k+1, n);}
}
signed main()
{
q=read();
n1=read(); k1=read();
a=read(); b=read(); Mod=read();
for (int i=1; i<q; ++i) c[i]=read();
for (int i=1; i<q; ++i) d[i]=read();
// for (int i=1; i<20; ++i) {C[i][1]=1; cout<<C[i][1]*i<<' '; for (int j=2; j<=i; ++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod, cout<<C[i][j]*i<<' '; cout<<endl;}
task::init();
ll lst=task::solve(n1, k1);
printf("%lld\n", lst);
for (int i=1; i<q; ++i) {
n1=(a*lst+c[i])%Mod+1, k1=(b*lst+d[i])%n1+1;
lst=task::solve(n1, k1);
printf("%lld\n", lst);
}
// cout<<task::solve(4, 2)<<endl;
return 0;
}