[BZOJ 4815] [Cqoi2017]小Q的表格 解题报告

来源:互联网 发布:windows安装jdk 编辑:程序博客网 时间:2024/06/16 03:37

4815: [Cqoi2017]小Q的表格
Description
小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之后的结
果。
Input
第1行包含两个整数m,n,表示共有m次操作,所有操作和查询涉及到的行编号和列编号都不超过n。
接下来m行,每行4个整数a,b,x,k表示把第a行b列的数改成x,然后把它能够波及到的所有格子全部修改,保证修改
之后所有格子的数仍然都是整数,修改完成后计算前k行前k列里所有数的和。
1<=m<=10000,1<=a,b,k<=N<=4*10^6,0<=x<=10^18
Output
输出共m行,每次操作之后输出1行,表示答案mod 1,000,000,007之后的结果。
Sample Input

3 3

1 1 1 2

2 2 4 3

1 2 4 2
Sample Output

9

36

14

写在前面,考场上爆0了。然后拿到数据后发现我对于他所说的整数理解错了,应该是修改之后就是整数,而不是修改的数是a*b的倍数,僵硬啊!!!
首先,拿到题目后进行仔细研究(在纸上疯狂的画修改一个点会影响到的格子)可以发现,修改一个点影响的格子,一定会有(p,p),且p为GCD(x,y)
然后,根据狗眼观察法,可发现,修改(p,p)与修改(1,1)在一定意义下等价,即我们只用算出修改(1,1)点,对于k行k列的影响即可
接着,继续根据狗眼观察法可发现,只有GCD(X,Y)==1的点才会在修改(1,1)的情况下被修改,所以我们筛一下phi,因为n以内与n互质的数的和为n*phi[n]/2(若n-k与n互质,则k与n互质,两两对应一下即可推)
便有预处理,ans[1]=1;
for(int i=2;i<=n;i++)ans[i]=(ans[i-1]+(long long)phi[i]*i%mo*i%mo)%mo;
你们或许会问(/2)去哪里了呢,因为关于对角线对称,所以我们这么预处理一下,就是i以内将(1,1)的点权修改1会影响多少了
再接着前面的说,修改(p,p)与修改(1,1)在一定意义下等价,即修改(p,p),就修改了ans[k/p]这么多。
至于怎么实现嘛,m^2暴力呀,记录修改,对于每次询问暴力修改就好了呀
应该讲的很清楚了吧,下面是代码

#include<iostream>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<iomanip>#include<cmath>#include<ctime>using namespace std;const long long mo=1000000007;long long ans[4000005],jl[4000005],top;bool v[4000005],bj[4000005];int prime[1000005],cnt,phi[4000005],m,n,stk[4000005];long long ryl(){    long long r=0,z=1;    char c=getchar();    while(c<'0'||c>'9'){        if(c=='-')z=-1;c=getchar();    }    while(c>='0'&&c<='9')r=r*10+c-'0',c=getchar();    return r*z;}void makeprime(){    for(int i=2;i<=n;i++){        if(!v[i])prime[++cnt]=i,phi[i]=i-1;        for(int j=1;j<=cnt&&i*prime[j]<=n;j++){            v[i*prime[j]]=1;            if(i%prime[j]==0){                phi[i*prime[j]]=phi[i]*prime[j];                break;            }            phi[i*prime[j]]=phi[i]*(prime[j]-1);        }    }}int main(){    m=ryl();n=ryl();     makeprime();    ans[1]=1;    for(int i=2;i<=n;i++)ans[i]=(ans[i-1]+(long long)phi[i]*i%mo*i%mo)%mo;    for(int i=1;i<=m;i++){        long long x=ryl(),y=ryl(),v=ryl(),k=ryl();        long long now=__gcd(x,y);        jl[now]=v/(x/now)/(y/now)%mo;        x=now;        if(!bj[x])stk[++top]=x,bj[x]=1;        long long anss=0;        if(k%2==0)anss=(k/2)*(k/2)%mo*(k+1)%mo*(k+1)%mo;        else anss=k*k%mo*((k+1)/2)%mo*((k+1)/2)%mo;         for(int j=1;j<=top;j++){            x=stk[j];            anss=(anss+((jl[x]-x*x%mo)%mo+mo)%mo*(ans[k/x])%mo)%mo;        }        cout<<anss<<'\n';    }    return 0;}
0 0