『ZOJ 3547』The Boss on Mars (容斥原理)
傳送門戳這裏qwq
題目描述
On Mars, there is a huge company called ACM (A huge Company on Mars), and it’s owned by a younger boss.
Due to no moons around Mars, the employees can only get the salaries per-year. There are nemployees in ACM, and it’s time for them to get salaries from their boss. All employees are numbered from 1 to n
Because the number of employees is so large that the boss of ACM must distribute too much money, he wants to fire the people whose work number is co-prime with n
題目翻譯(XJH版本)
又若幹年之後,XJH成為了一個上市企業的老板,然而是一個摳門的老板(XJH:???)。
XJH的公司裏面有n個員工,編號是1~n。每個人的工資是自己編號的四次方,例如,編號為5的員工,工資就是54=625。 (員工1:???)
然而,XJH覺得工資發的太多了,需要裁員。於是,決定把所有編號和自己互質的員工都裁掉(XJH的編號顯然是n,肥水不流外人田)。 現在,問:XJH裁員之後能省多少錢?
解題思路
我們直接一上來就能看出一種O(n)的做法,那就是一個數一個數的枚舉,如果這個數沒有被訪問過並且和n是互質的,那麽這個數的次方都與n互質,計算的過程中順便把vis標記一下,標準的O(n),標準的TLE。。。。
我們不妨轉換一下思路:我們不妨求所有於所有與n不互質的數的四次方之和,再用 ∑n^4 把它減掉,也能得到所有的結果。並且,1e8以內的數的質因子個數很少,所以這樣應該不會超時,但是還有一個難點——如何推出四次方求和公式?
我們退而求其次,不妨先求出更低次的求和公式:
這樣,我們就可以推出二次求和公式,以此類推,我們就可以得到4次求和公式:
既然有除,又有膜,所以我們就要用到逆元了。
比如n與3不互質,那和6,9,12,15也就不互質,那麽我們將這個數列除以3,就得到差為1的等差數列,這樣我們就很容易求了。運用容斥原理,二進制枚舉就可以了。
代碼
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define ll long long 6 using namespace std; 7 const int maxn=10050; 8 const ll MOD=1e9+7; 9 const ll ni=233333335; 10 bool pri[maxn]; 11 ll p[maxn],num[maxn]; 12 ll T,n,cnt=0,tot=0,ans; 13 inline void ini(){ 14 pri[1]=0; 15 for(register int i=2;i<maxn;i++){ 16 if(pri[i]){ 17 p[++cnt]=i; 18 for(register int j=2;j*i<maxn;j++)pri[i*j]=0; 19 } 20 } 21 } 22 inline ll ksm(ll a,ll b){ 23 ll c=1; 24 while(b){ 25 if(b&1)c=c*a%MOD; 26 a=a*a%MOD,b>>=1; 27 } 28 return c%MOD; 29 } 30 inline ll calc(ll x){ 31 ll y=x%MOD; 32 y=y*(x+1)%MOD; 33 y=y*(2*x+1)%MOD; 34 y=y*((3*x*x+3*x-1)%MOD)%MOD; 35 y=y*ni%MOD; 36 return y; 37 } 38 inline void resolve(ll x){ 39 for(register int i=1;i<=cnt;i++){ 40 if(p[i]>x)break; 41 if(x/p[i]*p[i]==x){ 42 num[++tot]=p[i]; 43 while(x/p[i]*p[i]==x)x/=p[i]; 44 } 45 } 46 if(x>1)num[++tot]=x; 47 } 48 int main(){ 49 memset(pri,1,sizeof(pri)); 50 ini(); 51 scanf("%lld",&T); 52 while(T--){ 53 memset(num,0,sizeof(num)); 54 tot=ans=0; 55 scanf("%lld",&n); 56 ans=calc(n); 57 resolve(n); 58 for(register ll i=1;i<(1<<tot);i++){ 59 ll tmp=1,cnt1=0; 60 for(register ll j=0;j<tot;j++){ 61 if(i&(1<<j)){ 62 cnt1++; 63 tmp=tmp*num[j+1]%MOD; 64 } 65 } 66 // 67 if(cnt1&1){ 68 ans=(ans-(calc(n/tmp)*ksm(tmp,4))%MOD+MOD)%MOD; 69 } 70 else { 71 ans=(ans+(calc(n/tmp)*ksm(tmp,4))%MOD+MOD)%MOD; 72 } 73 } 74 printf("%lld\n",(ans+MOD)%MOD); 75 } 76 }
聖誕快樂!!
『ZOJ 3547』The Boss on Mars (容斥原理)