問題 B: 奇數國
時間限制: 1 Sec 內存限制: 256 MB
提交: 82 解決: 44
[提交][狀態][討論版]
題目描述
在一片美麗的大陸上有100000個國家,記爲1到100000。這裏經濟發達,有數不盡的賬房,並且每個國家有一個銀行。某大公司的領袖在這100000個銀行開戶時都存了3大洋,他惜財如命,因此會不時地派小弟GFS清點一些銀行的存款或者讓GFS改變某個銀行的存款。該村子在財產上的求和運算等同於我們的乘法運算,也就是說領袖開戶時的存款總和爲3100000。這裏發行的軟妹面額是最小的60個素數(p1=2,p2=3,…,p60=281),任何人的財產都只能由這60個基本面額表示,即設某個人的財產爲fortune(正整數),則fortune=p1^k1*p2^k2*……p60^K60。
領袖習慣將一段編號連續的銀行裏的存款拿到一個賬房去清點,爲了避免GFS串通賬房叛變,所以他不會每次都選擇同一個賬房。GFS跟隨領袖多年已經摸清了門路,知道領袖選擇賬房的方式。如果領袖選擇清點編號在[a,b]內的銀行財產,他會先對[a,b]的財產求和(計爲product),然後在編號屬於[1,product]的賬房中選擇一個去清點存款,檢驗自己計算是否正確同時也檢驗賬房與GFS是否有勾結。GFS發現如果某個賬房的編號number與product相沖,領袖絕對不會選擇這個賬房。怎樣纔算與product不相沖呢?若存在整數x,y使得number*x+product*y=1,那麼我們稱number與product不相沖,即該賬房有可能被領袖相中。當領袖又賺大錢了的時候,他會在某個銀行改變存款,這樣一來相同區間的銀行在不同的時候算出來的product可能是不一樣的,而且領袖不會在某個銀行的存款總數超過1000000。
現在GFS預先知道了領袖的清點存款與變動存款的計劃,想請你告訴他,每次清點存款時領袖有多少個賬房可以供他選擇,當然這個值可能非常大,GFS只想知道對19961993取模後的答案。
輸入
第一行一個整數x表示領袖清點和變動存款的總次數。
接下來x行,每行3個整數ai,bi,ci。ai爲0時表示該條記錄是清點計劃,領袖會清點bi到ci的銀行存款,你需要對該條記錄計算出GFS想要的答案。ai爲1時表示該條記錄是存款變動,你要把銀行bi的存款改爲ci,不需要對該記錄進行計算。
輸出
輸出若干行,每行一個數,表示那些年的答案。
樣例輸入
6
013
115
013
117
013
023
樣例輸出
18
24
36
6
explanation
初始化每個國家存款都爲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個數。
提示
x≤100000,當ai=0時0≤ci−bi≤100000
說白了要求數列某一段乘積的歐拉函數.
根據歐拉定理,φ(n)=n*∏((p-1)/p) (p爲n的質因數)
一棵線段樹維護這一段乘積,並維護這一段有哪些質數。而題目中指出只會用到60個質數,那就很方便了,可以狀壓一下,用二進制記錄下有哪些質數,60剛好不會爆long long.
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mod 19961993
#define N 100000
#define ll long long
using namespace std;
int read()
{
int sum=0,f=1;char x=getchar();
while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
while(x>='0'&&x<='9'){sum=(sum<<3)+(sum<<1)+x-'0';x=getchar();}
return sum*f;
}
struct tree
{
int l,r; ll h,sum;
}t[N*4+100];
int m;
ll s1,s2,ans,xp[65],hh[65],pri[65]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,};
ll cheng(ll x,ll m)
{
ll ans=1;
while(m)
{
if(m&1)ans=ans*x%mod;
x=x*x%mod;
m>>=1;
}
return ans;
}
void build(int l,int r,int x)
{
t[x].l=l;t[x].r=r;
if(l==r)
{
t[x].h=3;t[x].sum=xp[1];
return;
}
int mid=l+r>>1;
build(l,mid,x*2);
build(mid+1,r,x*2+1);
t[x].h=t[x*2].h*t[x*2+1].h%mod;
t[x].sum=t[x*2].sum|t[x*2+1].sum;
}
void c(int l,int k,int x)
{
if(t[x].l==t[x].r)
{
t[x].h=k;t[x].sum=0;
for(int i=0;i<60;i++)
if(k%pri[i]==0)t[x].sum|=xp[i];
return;
}
int mid=t[x].l+t[x].r>>1;
if(l<=mid)c(l,k,x*2);
else c(l,k,x*2+1);
t[x].h=t[x*2].h*t[x*2+1].h%mod;
t[x].sum=t[x*2].sum|t[x*2+1].sum;
}
void q(int l,int r,int x)
{
if(t[x].l>=l&&t[x].r<=r)
{
s2=s2*t[x].h%mod;
s1|=t[x].sum;
return;
}
int mid=t[x].l+t[x].r>>1;
if(l<=mid)q(l,r,x*2);
if(r>mid)q(l,r,x*2+1);
}
int main()
{
m=read();
for(int i=0;i<60;i++)
{
hh[i]=cheng(pri[i],mod-2);
hh[i]=(pri[i]-1)*hh[i]%mod;
}
xp[0]=1;for(int i=1;i<=60;i++)xp[i]=xp[i-1]*2LL;
build(1,N,1);
int x,a,b;
while(m--)
{
x=read();a=read();b=read();
if(!x)
{
s1=0;ans=s2=1;q(a,b,1);
for(int i=0;i<60;i++)if(xp[i]&s1)(ans*=hh[i])%=mod;
printf("%lld\n",ans*s2%mod);
}
else c(a,b,1);
}
}