zoukankan      html  css  js  c++  java
  • [洛谷P3700] CQOI2017 小Q的表格

    问题描述

    小Q是个程序员。

    作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理。每当小Q不知道如何解决时,就只好向你求助。

    为了完成任务,小Q需要列一个表格,表格有无穷多行,无穷多列,行和列都从1开始标号。为了完成任务,表格里面每个格子都填了一个整数,为了方便描述,小Q把第a行第b列的整数记为f(a,b)。为了完成任务,这个表格要满足一些条件:

    (1)对任意的正整数a,b,都要满足f(a,b)=f(b,a);

    (2)对任意的正整数a,b,都要满足b×f(a,a+b)=(a+b)×f(a,b)。

    为了完成任务,一开始表格里面的数很有规律,第a行第b列的数恰好等于a×b,显然一开始是满足上述两个条件的。为了完成任务,小Q需要不断的修改表格里面的数,每当修改了一个格子的数之后,为了让表格继续满足上述两个条件,小Q还需要把这次修改能够波及到的全部格子里都改为恰当的数。由于某种神奇的力量驱使,已经确保了每一轮修改之后所有格子里的数仍然都是整数。为了完成任务,小Q还需要随时获取前k行前k列这个有限区域内所有数的和是多少,答案可能比较大,只需要算出答案mod1,000,000,007之后的结果。

    输入格式

    输入文件第1行包含两个整数m,n,表示共有m次操作,所有操作和查询涉及到的行编号和列编号都不超过n。

    接下来m行,每行4个整数a,b,x,k,表示把第a行b列的数改成x,然后把它能够波及到的所有格子全部修改,保证修改之后所有格子的数仍然都是整数,修改完成后计算前k行前k列里所有数的和。

    输出格式

    输出共m行,每次操作之后输出1行,表示答案mod1,000,000,007之后的结果。

    样例输入

    3 3
    1 1 1 2
    2 2 4 3
    1 2 4 2

    样例输出

    9
    36
    14

    数据范围

    对于 100%的测试点,1 ≤ m ≤ 10^4, 1 ≤ a,b,k ≤ n ≤ 4×10^6, 0 ≤ x < 10^18。

    解析

    将第二个条件转化一下可得:(frac{f(a,b)}{ab}=frac{f(a,a+b)}{a(a+b)})。这和更相减损法类似,我们可以得到 (frac{f(a,b)}{ab}=frac{f(d,d)}{d^2} (d=gcd(a,b)))。推一推式子:

    [egin{aligned} sum_{i=1}^ksum_{j=1}^kf(i,j)&=sum_{d=1}^kf(d,d)sum_{i=1}^{lfloor frac{k}{d} floor}sum_{j=1}^{lfloor frac{k}{d} floor}ij[gcd(i,j)=1]\ end{aligned} ]

    交换 (i,j) 对结果没有影响,我们可以只计算一半,注意减掉重复计算的 (i=j) 的情况。我们对右边搞一下:

    [egin{aligned} sum_{i=1}^nsum_{j=1}^nij[gcd(i,j)=1]&=2sum_{i=1}^nsum_{j=1}^iijsum_{d|i,d|j}mu(d)-sum_{i=1}^n i^2[gcd(i,i)=1]\ &=2sum_{i=1}^nisum_{d|i} mu(d)sum_{j=1}^{i/d}jd-1\ &=2sum_{i=1}^nisum_{d|i}mu(d)frac{frac{i}{d} imes(frac{i}{d}+1)}{2} imes d-1\ &=sum_{i=1}^ni^2sum_{d|i}mu(d)(frac{i}{d}+1)-1\ &=sum_{i=1}^ni^2 (sum_{d|i}mu(d) imes frac{i}{d}+sum_{d|i}mu(d))-1\ &=sum_{i=1}^ni^2+phi(i)+sum_{i=1}^ni^2[i=1]-1\ &=sum_{i=1}^n i^2+phi(i) end{aligned} ]

    那么原式等于

    [sum_{d=1}^kf(d,d)sum_{i=1}^{lfloor frac{k}{d} floor} i^2+phi(i) ]

    后面可以数论分块搞。而 (f) 的修改可以通过分块维护前缀和来维护。具体的,每一块的最后一个点维护整个序列的前缀和,其余点只维护块内前缀和。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #define N 4000002
    using namespace std;
    const int mod=1000000007;
    int n,m,i,j,prime[N],cnt,b[N],gap;
    long long phi[N],sum[N],s[N];
    bool vis[N];
    long long read()
    {
    	char c=getchar();
    	long long w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    int gcd(int a,int b)
    {
    	if(!b) return a;
    	return gcd(b,a%b);
    }
    int poww(int a,int b)
    {
    	long long ans=1,base=a;
    	while(b){
    		if(b&1) ans=ans*base%mod;
    		base=base*base%mod;
    		b>>=1;
    	}
    	return ans;
    }
    void change(int x,int v)
    {
    	for(int i=x;b[i]==b[x];i++) sum[i]=(sum[i]+v)%mod;
    	for(int i=(b[x]+1)*gap;i<=n;i+=gap) sum[i]=(sum[i]+v)%mod;
    	if(n%gap!=0&&b[n]!=b[x]) sum[n]=(sum[n]+v)%mod;
    }
    int ask(int x)
    {
    	if(x%gap==0||x==n) return sum[x];
    	return (sum[x]+sum[(b[x]-1)*gap])%mod;
    }
    signed main()
    {
    	m=read();n=read();
    	phi[1]=1;
    	for(i=2;i<=n;i++){
    		if(!vis[i]){
    			prime[++cnt]=i;
    			phi[i]=i-1;
    		}
    		for(j=1;j<=cnt;j++){
    			if(i*prime[j]>n) break;
    			vis[i*prime[j]]=1;
    			if(i%prime[j]) phi[i*prime[j]]=phi[i]*(prime[j]-1)%mod;
    			else{
    				phi[i*prime[j]]=prime[j]*phi[i]%mod;
    				break;
    			}
    		}
    	}
    	for(i=1;i<=n;i++) phi[i]=phi[i]*i%mod*i%mod;
    	for(i=1;i<=n;i++) phi[i]=(phi[i-1]+phi[i])%mod;
    	gap=sqrt(1.0*n);
    	for(i=1;i<=n;i++) b[i]=(i-1)/gap+1;
    	long long tmp=0;
    	for(i=1;i<=n;i++){
    		tmp=(tmp+1LL*i*i%mod)%mod;s[i]=1LL*i*i%mod;
    		if(i%gap==0||i==n) sum[i]=tmp;
    		else if((i-1)%gap!=0) sum[i]=(sum[i-1]+1LL*i*i%mod)%mod;
    		else sum[i]=1LL*i*i%mod;
    	}
    	for(i=1;i<=m;i++){
    		int a=read(),b=read();
    		long long x=read(),ans=0;
    		int k=read();
    		int d=gcd(a,b);
    		long long val=1LL*x%mod*d%mod*d%mod*poww(1LL*a*b%mod,mod-2)%mod;
    		change(d,(val-s[d]+mod)%mod);s[d]=val;
    		for(int l=1,r;l<=k;l=r+1){
    			r=k/(k/l);
    			ans=(ans+1LL*(ask(r)-ask(l-1)+mod)%mod*phi[k/l]%mod)%mod;
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    .NET程序员面试小技巧
    .ashx一般处理程序
    地铁线路图的设计与实现
    BS与CS的区别
    关于sqlserver2005异地自动备份
    二问唐骏:究竟是打工好还是创业好
    再燃中国激情 “创业指南针”团队首推创业专著
    读者看《赢道:成功创业者的28条戒律》
    创业必看:中国八大草根富豪发家史
    让你快乐,是我恒久写诗的唯一目的
  • 原文地址:https://www.cnblogs.com/LSlzf/p/13534860.html
Copyright © 2011-2022 走看看