BZOJ 4815 [Cqoi2017]小Q的表格 ——欧拉函数
把式子化简一波。
发现一个比较厉害的性质:每个点只能影响到行列下标$gcd$与它相同的点。
然后就可以计算$\sum_{g<=k}f(g,g)*\sum_{i<=k}\sum_{j<=k}[gcd(i,j)==g](i/g)*(i/g)$
然后考虑它的意义,直接发现计算出$i*i*\phi(i)$的前缀和就可以下界函数分块计算了。
这样子还是过不了。考虑修改次数比较少,考虑分块维护,就可以$O(1)$查询了。
复杂度$m\sqrt {n}$
#include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (ll i=j;i<=k;++i) #define D(i,j,k) for (ll i=j;i>=k;--i) #define ll long long #define mp make_pair const ll md=1000000007; void Finout() { freopen("table.in","r",stdin); freopen("table.out","w",stdout); } #define maxn 10000001 int a[maxn],phi[maxn],f[maxn]; int vis[maxn],pri[maxn],top=0,m,n; ll Getll() { ll x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } void Shaker() { phi[1]=1; F(i,2,n) { if (!vis[i]) pri[++top]=i,phi[i]=i-1; for (ll j=1;j<=top&&(ll)i*pri[j]<=(ll)n;++j) { vis[i*pri[j]]=1; if (i%pri[j]==0) { phi[i*pri[j]]=phi[i]*pri[j]; break; } else phi[i*pri[j]]=phi[i]*phi[pri[j]]; } } F(i,1,maxn-1) phi[i]=phi[i]*i%md*i%md+phi[i-1],phi[i]%=md; } int sum[50005],pre[maxn]; int L[50005],R[50005],bel[maxn],T,tot=0; void add(ll x,ll d) { F(i,x,R[bel[x]]) { pre[i]+=d,pre[i]%=md; } F(i,bel[x],tot) { sum[i]+=d,sum[i]%=md; } } ll gs(ll x) { if (x==0) return 0; ll ret=0; ret=sum[bel[x]-1]+pre[x]; ret%=md; return ret; } ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);} ll cal(ll k) { ll ret=0; for (ll i=1,last=0;i<=k;i=last+1) { last=k/(k/i); ret+=phi[k/last]*((gs(last)-gs(i-1))%md); ret%=md; } return (ret+md)%md; } void init() { T=sqrt(n); //printf("Block Size is %d\n",T); for (ll i=1;i<=n;i+=T) { L[++tot]=i; R[tot]=i+T-1; } R[tot]=n; F(i,1,tot) F(j,L[i],R[i]) bel[j]=i; } int main() { m=Getll();n=Getll(); init(); Shaker(); F(i,1,n) a[i]=((ll)i*i)%md; F(i,1,n) (a[i]+=a[i-1])%=md; F(i,1,tot) sum[i]=a[R[i]]; F(i,1,tot) { pre[L[i]]=(a[L[i]]-a[L[i]-1])%md; F(j,L[i]+1,R[i]) pre[j]=(pre[j-1]+a[j]-a[j-1])%md; } sum[0]=0; F(i,1,m) { ll a,b,k,x; a=Getll();b=Getll();x=Getll();k=Getll(); ll g=gcd(a,b); add(g,-gs(g)+gs(g-1)); ll tmp=x/(a/g)/(b/g); tmp%=md; add(g,tmp); printf("%lld\n",cal(k)); } }