zoukankan      html  css  js  c++  java
  • 【CQOI2017】小Q的表格

    【CQOI2017】小Q的表格

    稍加推导就会发现(f(a,b)=acdot bcdot h(gcd(a,b)))

    初始时(h(n)=1)

    询问前(k)(k)列时我们就反演:

    [egin{align} displaystyle ans&=sum_{g=1}h(g)cdot g^2sum_{a=1}^{lfloorfrac{k}{g} floor} sum_{b=1}^{lfloorfrac{k}{g} floor}acdot bsum_{d|a,d|b}mu(d)\ &=sum_{g=1}h(g)cdot g^2sum_{d=1}^{lfloorfrac{k}{g} floor}d^2cdot mu(d)cdot sum^2(lfloorfrac{k}{gd} floor) end{align} ]

    其中(displaystyle sum(n)=sum_{i=1}^ni)

    我们设

    [displaystyle q(n)=sum_{d=1}^n d^2cdot mu(d)cdot sum^2(lfloorfrac{n}{d} floor) ]

    我们可以在(O(NlogN))的时间内求出所有的(q(i))

    考虑(q(n))(q(n-1))的区别:只有在(d|n)的时候才会产生。

    所以:

    [displaystyle q(n)=q(n-1)+sum_{d|n}d^2mu(d)(sum^2(frac{n}{d})-sum^2(frac{n}{d}-1)) ]

    于是我们就可以数论分块处理询问。

    但是如果我们用树状数组处理修改,那么我们的复杂度就多了一个(log),无法接受。所以我们牺牲修改时间来平衡询问时间。

    使用分块来维护(h(g)cdot g^2)的前缀和。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 4000005
    
    using namespace std;
    inline ll Get() {ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    int n,m;
    ll a,b;
    ll x,k;
    const ll mod=1e9+7;
    int gcd(int a,int b) {return !b?a:gcd(b,a%b);}
    bool vis[N];
    int p[N],u[N];
    ll g[N],f[N],sum[N];
    ll inv[N],bel[N];
    const int blk=2e3+7;
    int add[blk];
    
    void pre(int n) {
    	g[1]=u[1]=1;
    	for(int i=2;i<=n;i++) {
    		if(!vis[i]) {
    			g[i]=mod+1-inv[i];
    			p[++p[0]]=i;
    		}
    		for(int j=1;j<=p[0]&&1ll*i*p[j]<=n;j++) {
    			vis[i*p[j]]=1;
    			if(i%p[j]==0) {
    				g[i*p[j]]=g[i];
    				break;
    			}
    			g[i*p[j]]=1ll*(mod+1-inv[p[j]])*g[i]%mod;
    		}
    	}
    	for(int i=1;i<=n;i++) {
    		g[i]=(1ll*g[i]*i%mod*i%mod*i%mod+g[i-1])%mod;
    	}
    }
    
    void Add(int v,int x) {
    	int b=bel[v];
    	for(int i=(b-1)*blk+1;bel[i]==b;i++) (f[i]+=add[b])%=mod;
    	add[b]=0;
    	for(int i=v;bel[i]==b;i++) (f[i]+=x)%=mod;
    	for(int i=b+1;i<=bel[n];i++) (add[i]+=x)%=mod;
    }
    
    ll query(int v) {return (f[v]+add[bel[v]])%mod;}
    
    int solve(int n) {
    	ll ans=0,last=0;
    	for(int i=1;i<=n;i=last+1) {
    		last=n/(n/i);
    		(ans+=1ll*(query(last)-query(i-1)+mod)*g[n/i])%=mod;
    	}
    	return ans;
    }
    
    int main() {
    	m=Get(),n=Get();
    	inv[1]=inv[0]=1;
    	for(int i=2;i<=n;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    	pre(n);
    	for(int i=1;i<=n;i++) bel[i]=(i-1)/blk+1;
    	for(int i=1;i<=n;i++) f[i]=1ll*i*i%mod;
    	for(int i=1;i<=n;i++) f[i]=(f[i]+f[i-1])%mod;
    	while(m--) {
    		a=Get(),b=Get(),x=Get(),k=Get();
    		int g=gcd(a,b);
    		ll now=x%mod*inv[a]%mod*inv[b]%mod*g%mod*g%mod;
    		now=(now-(query(g)-query(g-1))+mod)%mod;
    		Add(g,now);
    		int ans=0;
    		cout<<solve(k)<<"
    ";
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    C#相关时间DateTime格式化
    获得服务器硬件信息(CPUID、硬盘号、主板序列号、IP地址等)
    时间正则表达式小叙
    Jmeter 压力测试学习8--断言
    Jmeter压力测试学习7--压测带token的接口
    Jmeter压测学习6---登录参数CSV
    Jmeter压测学习5---HTTP Cookie管理器
    Jmeter压测学习4--XPath提取器
    Jmeter压测学习3---通过正则表达式提取token
    Jmeter压测学习2---提取token,并关联参数
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10507687.html
Copyright © 2011-2022 走看看