P3700 [CQOI2017] 小 Q 的表格 题解
Last_Flame · · 题解
UPD20231121
现在看当年写的这个题解,感觉真的太稚嫩了,趁没人看到这个黑历史重置一遍。
思路
蒟蒻没有什么数论基础,决定乱搞,找出了题目的一些性质。
我们在修改某一个位置的数的时候,表格中一定会有其他一些位置会同步修改。
先尝试找出会同步修改的位置。
一眼看不出来,于是就在 Excel 里面弄了张图,大概长这样:
修改任意绿色位置,所有绿色位置都会被修改。
然后我们发现,对于位置
分析条件
即修改位置
然后我们来看到条件
结合条件
那么假如我们修改了位置
这个东西看起来像什么?
所以说,假如修改位置
(所以这道题的题面也是互质表的一种画法,使用 Excel 自带的复制功能可以很方便地画出上文的那张表)
好了,我们已经知道修改任一位置,应该同时修改的位置有哪些了。但是到底要怎么求出数和呢?
条件
-
f(a,a+b) = \frac{a+b}{b} \times f(a,b) -
f(a+b,a) = \frac{a+b}{b} \times f(a,b)
简单概括一下,就是说对于同一行的两个位置,它们的数之比等于列数之比;对于同一列的两个位置,它们的数之比等于行数之比。初始时,
还能发现,当我们把某位置的值修改为原来的
那么我们考虑未修改时
这个可以用自然数幂方求和公式
然后对于修改操作,由于是一次性修改
但是我不正常,毕竟当时考试做到这道题的时候我还不会莫反,我直接考虑使用欧拉函数!
这个修改操作就是给定
但是这道题我们要求的是:
那么我们就是要求这个函数(需要注意
那么原式可以化为:
由于每次修改后,所有修改的位置都会变为原来的值的倍数,那么对于每个
总复杂度
code
#include<bits/stdc++.h>
using namespace std;
const int mn=1048576,mod=1e9+7;
int m,n,k;
long long a,b,x;
vector<int> prime,chl;
int ppt;
int answ;
long long pgcd,pgcd2;
long long mpt,ans[4*mn],pans;
long long sumphin[4*mn],phi[4*mn],phin[4*mn];
long long ch[4*mn];
bool isphi[4*mn],isch[4*mn];
bitset<4*mn> isprime;
int getgcd(int x1,int x2){
if(x1<x2) swap(x1,x2);
while(x2>0){
x1%=x2;
swap(x1,x2);
}
return x1;
}
void euler(){
phi[1]=1;sumphin[1]=1;phin[1]=1;sumphin[1]=1;
isprime.set();
for(int i=2;i<=n;i++){
if(isprime[i]){
prime.push_back(i);
phi[i]=i-1;
}
for(int i1=0,pi;i1<prime.size();i1++){
pi=i*prime[i1];
if(pi>n) break;
isprime[pi]=false;
if(i%prime[i1]==0){
phi[pi]=phi[i]*prime[i1];
break;
}
else phi[pi]=phi[i]*phi[prime[i1]];
}
}
for(int i=2;i<=n;i++){
phin[i]=phi[i]*i/2;
phin[i]%=mod;
phin[i]*=i;
phin[i]%=mod;
sumphin[i]=sumphin[i-1]+(phin[i])*2;
sumphin[i]%=mod;
}
return;
}
int main(){
cin>>m>>n;
for(int i=1;i<=n;i++){
mpt+=2*i-1;
mpt%=mod;
ans[i]=ans[i-1]+mpt*i;
ans[i]%=mod;
}
euler();
for(int i=1;i<=m;i++){
cin>>a>>b>>x>>k;
pgcd=getgcd(a,b);
pgcd2=pgcd*pgcd;
ch[pgcd]=x/((a*b)/pgcd2);
ch[pgcd]%=mod;
if(!isch[pgcd]){
chl.push_back(pgcd);
isch[pgcd]=true;
}
pans=ans[k];
for(int i1=0;i1<chl.size();i1++){
answ=k/chl[i1];
pans-=((sumphin[answ]*chl[i1])%mod)*chl[i1];
pans+=sumphin[answ]*ch[chl[i1]];
pans%=mod;
}
if(pans<0) pans+=mod;
cout<<pans<<endl;
}
return 0;
}