题解 点点的计算

传送门

发现 \(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;
}
posted @ 2022-01-20 11:16  Administrator-09  阅读(1)  评论(0编辑  收藏  举报