奇数国
题目描述
在一片美丽的大陆上有\(10^5\)个国家,记为\(1\)到\(10^5\)。这里经济发达,有数不尽的账房,并且每个国家有一个银行。某大公司的领袖在这\(10^5\)个银行开户时都存了\(3\)大洋,他惜财如命,因此会不时地派小弟GFS清点一些银行的存款或者让GFS改变某个银行的存款。该村子在财产上的求和运算等同于我们的乘法运算,也就是说领袖开户时的存款总和为\(3^{10^5}\)。这里发行的软妹面额是最小的\(60\)个素数(\(p_1=2,p_2=3,\cdots,p_{60}=281\)),任何人的财产都只能由这\(60\)个基本面额表示,即设某个人的财产为\(fortune\)(正整数),则\(fortune=p_1^{k_1}p_2^{k_2}\cdots p_{60}^{k_{60}}\)。
领袖习惯将一段编号连续的银行里的存款拿到一个账房去清点,为了避免GFS串通账房叛变,所以他不会每次都选择同一个账房。GFS跟随领袖多年已经摸清了门路,知道领袖选择账房的方式。如果领袖选择清点编号在\([a,b]\)内的银行财产,他会先对\([a,b]\)的财产求和(计为\(product\)),然后在编号属于\([1,product]\)的账房中选择一个去清点存款,检验自己计算是否正确同时也检验账房与GFS是否有勾结。GFS发现如果某个账房的编号\(number\)与\(product\)相冲,领袖绝对不会选择这个账房。怎样才算与\(product\)不相冲呢?若存在整数\(x\),\(y\)使得\(number\times x+product\times y=1\),那么我们称\(number\)与\(product\)不相冲,即该账房有可能被领袖相中。当领袖又赚大钱了的时候,他会在某个银行改变存款,这样一来相同区间的银行在不同的时候算出来的\(product\)可能是不一样的,而且领袖不会在某个银行的存款总数超过\(10^6\)。
现在GFS预先知道了领袖的清点存款与变动存款的计划,想请你告诉他,每次清点存款时领袖有多少个账房可以供他选择,当然这个值可能非常大,GFS只想知道对\(19961993\)取模后的答案。
输入格式
第一行一个整数\(x\),表示领袖清点和变动存款的总次数。
接下来\(x\)行,每行三个整数\(a_i\),\(b_i\),\(c_i\)。\(a_i\)为\(0\)时表示该条记录是清点计划,领袖会清点\(b_i\)到\(c_i\)的银行存款,你需要对该条记录计算出GFS想要的答案。\(a_i\)为\(1\)时表示该条记录是存款变动,你要把银行\(b_i\)的存款改为\(c_i\),不需要对该记录进行计算。
输出格式
输出若干行,每行一个整数,表示那些年的答案。
输入输出样例
输入
6
0 1 3
1 1 5
0 1 3
1 1 7
0 1 3
0 2 3
输出
18
24
36
6
说明/提示
【样例解释】
初始化每个国家存款都为\(3\);
\(1\)到\(3\)的\(product\)为\(27\),\([1,27]\)与\(27\)不相冲的有\(18\)个数;
\(1\)的存款变为\(5\);
\(1\)到\(3\)的\(product\)为\(45\),\([1,45]\)与\(45\)不相冲的有\(24\)个数;
\(1\)的存款变为\(7\);
\(1\)到\(3\)的\(product\)为\(63\),\([1,63]\)与\(63\)不相冲的有\(36\)个数;
\(2\)到\(3\)的\(product\)为\(9\),\([1,9]\)与\(9\)不相冲的有\(6\)个数。
【数据规模和约定】
对于\(20\%\)的数据,\(x\le 10^4\),当\(a_i=0\quad 0\le c_i-b_i\le 10^2\),\(product\le 10^{18}\)。
对于\(50\%\)的数据,\(x\le 5\times 10^4\),当\(a_i=0\quad 0\le c_i-b_i\le 10^4\)。
对于\(100\%\)的数据,\(x\le 10^5\),当\(a_i=0\quad 0\le c_i-b_i\le 10^5\)。
欧拉函数+树状数组
证明定理
- 定理:如果任意整数\(a\)和\(b\)不都为\(0\),则\(gcd(a,b)\)是\(a\)与\(b\)的线性组合集\(\{ax+by:x,y\in Z\}\)中的最小正元素。
- 证明:设\(s\)是\(a\)与\(b\)的线性组合集中的最小正元素,并且对某个\(x,y\in Z\),有\(s=ax+by\)。设\(q=\lfloor a/s\rfloor\),则\(a\ mod\ s=a-qs=a-q(ax+by)=a(1-qx)+b(-qy)\)。因此,\(a\ mod\ s\)也是\(a\)与\(b\)的一个线性组合。由于\(0\le a\ mod\ s<s\),故有\(a\ mod\ s=0\)。因此有\(s|a\),类似地,可得到\(s|b\)。因此,\(s\)是\(a\)与\(b\)的公约数,所以\(s\le gcd(a,b)\)。因为\(gcd(a,b)\)能同时被\(a\)与\(b\)整除,并且\(s\)是\(a\)与\(b\)的一个线性组合,所以\(gcd(a,b)|s\)。但由于\(gcd(a,b)|s\)和\(s>0\),因此\(gcd(a,b)\le s\)。将上面已证明的\(s\le gcd(a,b)\)与\(gcd(a,b)\le s\)结合起来,得到\(gcd(a,b)=s\),因此证明了\(s\)是\(a\)与\(b\)的最大公约数。
欧拉函数
由于存在整数\(x\),\(y\)使得\(number\times x+product\times y=1\),\(1\)一定是\(number\)和\(product\)线性组合集中的最小正元素。根据上述定理,就有\(gcd(number,product)=number\times x+product\times y=1\)。
这样,本题便是求\([1,product]\)中有多少个与\(product\)互质的数,即\(\phi(product)\)。
- 欧拉函数:\(\phi(x)=x\prod_{i=1}^n(1-\frac{1}{p_i})\),其中\(p_1,p_2,\cdots,p_n\)为\(x\)的所有质因数,\(x\)是不为\(0\)的整数。
由于欧拉函数的计算过程中有除法参与,我们需要计算除数的乘法逆元。
- 乘法逆元:对于两个整数\(a\)和\(p\),存在一个\(x\)使得\(ax\equiv 1(mod\ p)\),我们称\(x\)为\(a\)关于\(p\)的乘法逆元。
这样,当我们计算\(\frac{a}{b}mod\ p\)时,设\(x\)为\(b\)关于\(p\)的乘法逆元,则\(\frac{a}{b}mod\ p=\frac{a}{b}bx\ mod\ p=ax\ mod\ p\),接下来我们只需要计算\(x\)。由于本题的模数\(19961993\)(也就是\(p\))是一个质数,我们可以使用费马小定理来计算乘法逆元。
- 费马小定理:如果\(p\)是一个质数,而整数\(a\)不是\(p\)的倍数,则有\(a^{p-1}\equiv 1(mod\ p)\)。
已知\(ab^{-1}\equiv ax(mod\ p)\),根据费马小定理又有\(b^{p-1}\equiv 1(mod\ p)\),两式相乘可得\(ab^{p-2}\equiv ax(mod\ p)\)。因为\(p\nmid a\),并且\(p\)是质数,所以\(gcd(a,p)=1\),则\(b^{p-2}\equiv x(mod\ p)\),那么\(b^{p-2}\)和\(x\)在\(mod\ p\)意义下相等,因此计算\(b^{p-2}\)即可。
由于\(product\)可能非常大,但其仅由\(281\)及其以下的质数积组成,我们只要知道每一种质因数有多少个,就能算出\(\phi(product)\)。
树状数组
对于每一次询问,我们需要查询给定范围内所有银行存款的每一种质因数一共有多少个,可以使用树状数组对其进行维护。对于每一种可能存在的质因数,我们建立一个树状数组(最多\(60\)个),记录该质因数的出现次数。
对于每一次修改,我们需要将该位置上原来的银行存款含有的每一种质因数的个数分别从树状数组中减掉,再加入新的质因数个数。
代码
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=65,MAXM=(int)1e5+5,MAXK=285,MOD=19961993;
int tre[MAXN][MAXM],tmp[MAXM][MAXN];
int prm[MAXN],ivs[MAXN];
bool vis[MAXK];
inline int lbt(int x){
return -x&x;
}
inline void upd(int mny,int i,int add){
while(i<=MAXM-5){
tre[mny][i]+=add;
i+=lbt(i);
}
}
inline int qry(int mny,int i){
int num=0;
while(i){
num+=tre[mny][i];
i-=lbt(i);
}
return num;
}
inline int pow(int x,int y){
int num=1;
while(y){
if(y&1)
num=1ll*num*x%MOD;
x=1ll*x*x%MOD;
y>>=1;
}
return num;
}
int main(){
int x,len=0;
for(register int i=1;i<=MAXM-5;i++){
upd(2,i,1);
tmp[i][2]=1;
}
for(register int i=2;i<=281;i++){
if(!vis[i]){
prm[++len]=i;
ivs[len]=pow(i,MOD-2);
}
for(register int j=1;j<=len&&i*prm[j]<=281;j++){
vis[i*prm[j]]=1;
if(!(i%prm[j]))
break;
}
}
scanf("%d",&x);
while(x--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(!a){
int ans=1;
for(register int i=1;i<=len;i++){
int x=qry(i,c)-qry(i,b-1);
if(x)
ans=1ll*ans*pow(prm[i],x)%MOD*(prm[i]-1)%MOD*ivs[i]%MOD;
}
printf("%d\n",ans);
}
else for(register int i=1;i<=len;i++){
upd(i,b,-tmp[b][i]);
tmp[b][i]=0;
while(!(c%prm[i])){
tmp[b][i]++;
c/=prm[i];
}
upd(i,b,tmp[b][i]);
}
}
return 0;
}

浙公网安备 33010602011771号