hdu 4407 Sum (容斥原理)
阿新 • • 發佈:2018-11-05
題目連結:hdu 4407
題意:
給一個長度為n的序列,序列由1~n依次組成。
對序列執行兩種操作:
1.查詢[x,y]內與p互素的數的和;
2.修改第x數為c.
題解:
這題我們可以先不管操作2,就按操作1去搞,因為資料很小,完全可以暴力解決操作2帶來的問題,
那麼我們可以求[1,n]內與p互素的和,最後結果就為 solve[1,y]-solve[1,x-1],再處理下操作2就行了,
求 [1,n]內與p互素的和,我們在另外一道題也做過,https://blog.csdn.net/LJD201724114126/article/details/82620754
簡單改下就行了。
#include<cstdio> #include<algorithm> #include<cstring> #include<map> #include<vector> using namespace std; typedef long long LL; const int maxn=400010; int prime[maxn],cnt; ///儲存素數,素數的個數 bool book[maxn]; map<int ,int >mp; vector<int> factor; int gcd(int a,int b) { if(!b) return a; else return gcd(b,a%b); } void Pri() ///線性篩素數 { memset(book,0,sizeof(book)); cnt=0; book[0]=book[1]=1; for(int i=2;i<maxn;i++) { if(!book[i]) prime[cnt++]=i; for(int j=0;j<cnt&&prime[j]*i<maxn;j++){ book[i*prime[j]]=1; if(i%prime[j]==0) break; } } } inline LL F(LL k,LL n){ return n*(n+1)/2*k; } LL solve(int n) ///解決[1,n] 內與p互素的和 { LL sum=F(1LL,n); ///計算前n項和 LL item=1<<factor.size(); ///素因子個數 LL ans=0; for(int i=1;i<item;i++) ///二進位制容斥,都差不多的 { int num=0,x=1; for(int j=0;j<factor.size();j++) { if(1&(i>>j)) { num++;x*=factor[j]; } } if(num&1) ans+=F(x,n/x); else ans-=F(x,n/x); } return sum-ans; } int main() { int ncase; Pri(); scanf("%d",&ncase); while(ncase--) { mp.clear(); ///注意此處,每次測試案例都要清零 int n,m; scanf("%d%d",&n,&m); while(m--){ int choice; scanf("%d",&choice); int x,y,c,p; if(choice==1){ scanf("%d%d%d",&x,&y,&p); if(x>y) swap(x,y); factor.clear(); ///初始化 int item=p; for(int i=0;i<cnt;i++) ///求出p的素因子 { if(prime[i]>item) break; if(item%prime[i]==0){ factor.push_back(prime[i]); while(item%prime[i]==0) item/=prime[i]; } } ///這是另外一種求素因子的方法 // for(int i=2;i*i<=item;i++){ // if(item%i==0){ // factor.push_back(i); // while(item%i==0) item/=i; // } // } if(item>1) factor.push_back(item); LL sum=solve(y)-solve(x-1); // printf("%lld %lld\n",solve(y),solve(x-1)); map<int ,int >::iterator it; for(it=mp.begin();it!=mp.end();it++) ///查詢操作2對結果有沒有影響 { int a=it->first,b=it->second; if(a>y||a<x) continue; if(gcd(a,p)==1) sum-=a; ///本來互素的要減掉 if(gcd(b,p)==1) sum+=b;///修改後互素的要加上 // printf("a=%d,b=%d\n",a,b); } printf("%lld\n",sum); } else{ scanf("%d%d",&x,&c); mp[x]=c; } } } return 8; }
我的標籤:做個有情懷的程式設計師。