1. 程式人生 > >51nod部分題解

51nod部分題解

容斥原理

51nod1434 區間LCM

跟容斥沒有關係。首先可以確定的一個結論是:對於任意正整數,有1*2*...*n | (k+1)*(k+2)*...*(k+n)。因為這就是$C_{n+k}^{k}$。

於是這題就有:m最多列舉到2n。

於是有一個做法:對n!分解質因數,然後列舉m的同時統計已獲得的所有質因數的次冪,全部不小於n!時即可推出。

複雜度肯定不大於$O(n\log n)$。

同時這裡有一個不會證的結論:找到n以內最大的$p^k$的數(p是質數),答案就是$2p^k$。

$O(n\log n)$

 1 #include<cstdio>
 2
#include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=2000010; 10 int T,n,tot,cnt[N],cnt2[N],pr[N],b[N],id[N]; 11 12 void init(int n){ 13 rep(i,2
,n){ 14 if (!b[i]) pr[++tot]=i,id[i]=tot; 15 for (int j=1; j<=tot && pr[j]*i<=n; j++){ 16 b[pr[j]*i]=1; 17 if (i%pr[j]==0) break; 18 } 19 } 20 } 21 22 int main(){ 23 init(1000000); 24 for (scanf("%d",&T); T--; ){ 25 scanf("
%d",&n); int g=1; 26 for (int i=1; i<=tot && pr[i]<=n; i++) 27 for (int j=pr[i]; j<=n; j*=pr[i]) g=max(g,j); 28 printf("%d\n",g*2); 29 } 30 return 0; 31 }
51nod1434

 

51nod1486 大大走格子

先把所有壞點按曼哈頓距離排序。

總方案數減去不合法方案的數量,列舉第一次走到的不合法格子(x,y),則答案就是(走合法格子到(x,y)的路徑數)*C(n-x,m-y)。而走合法格子到(x,y)的路徑數用同樣的方法算即可。

$O(n^2)$

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 using namespace std;
 5 
 6 const int N=200010,mod=1e9+7;
 7 int n,m,K,fac[N],inv[N],f[N];
 8 struct P{ int x,y; }p[N];
 9 bool operator <(const P &a,const P &b){ return (a.x==b.x) ? a.y<b.y : a.x<b.x; }
10 int C(int n,int m){ return n<m ? 0 : 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod; }
11 
12 int ksm(int a,int b){
13     int res=1;
14     for (; b; a=1ll*a*a%mod,b>>=1)
15         if (b & 1) res=1ll*res*a%mod;
16     return res;
17 }
18 
19 void init(int n){
20     fac[0]=1; rep(i,1,n) fac[i]=1ll*fac[i-1]*i%mod;
21     inv[n]=ksm(fac[n],mod-2);
22     for (int i=n-1; ~i; i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
23 }
24 
25 int main(){
26     scanf("%d%d%d",&n,&m,&K); init(n+m);
27     rep(i,1,K) scanf("%d%d",&p[i].x,&p[i].y);
28     sort(p+1,p+K+1); p[++K]=(P){n,m};
29     rep(i,1,K){
30         int res=C(p[i].x+p[i].y-2,p[i].x-1);
31         rep(j,1,i-1) if (p[j].x<=p[i].x && p[j].y<=p[i].y)
32             res=(res-1ll*f[j]*C(p[i].x-p[j].x+p[i].y-p[j].y,p[i].x-p[j].x)%mod+mod)%mod;
33         f[i]=res;
34     }
35     printf("%d\n",f[K]);
36     return 0;
37 }
51nod1486

 

51nod1678 lyk與gcd

簡單莫比烏斯容斥,答案是$\sum\limits_{d|x}\mu(d)\sum\limits_{d|i}a[i]$。

先線性篩出$\mu$,再對每個d維護$\sum\limits_{d|i}a[i]$,事先將每個數的因子全部預處理出來以減小常數。

$O(n*n^\frac{1.44}{\ln \ln n})$(據說n的因子個數是$n^\frac{1.44}{\ln \ln n}$級別的,當然肯定不滿)

 1 #include<vector>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=200010;
 9 int n,Q,tot,op,x,k,a[N],sm[N],miu[N],pr[N],b[N];
10 vector<int>ve[N];
11 
12 void init(int n){
13     rep(i,2,n){
14         if (!b[i]) pr[++tot]=i,miu[i]=-1;
15         for (int j=1; j<=tot && pr[j]*i<=n; j++){
16             b[pr[j]*i]=1;
17             if (i%pr[j]==0) { miu[pr[j]*i]=0; break; }
18                 else miu[pr[j]*i]=-miu[i];
19         }
20     }
21     rep(i,1,n) for (int j=i; j<=n; j+=i) ve[j].push_back(i);
22 }
23 
24 int main(){
25     scanf("%d%d",&n,&Q); miu[1]=1; init(100000);
26     rep(i,1,n){
27         scanf("%d",&a[i]); int ed=ve[i].size()-1;
28         rep(j,0,ed) sm[ve[i][j]]+=a[i];
29     }
30     rep(i,1,Q){
31         scanf("%d",&op);
32         if (op==1){
33             scanf("%d%d",&x,&k); int ed=ve[x].size()-1;
34             rep(i,0,ed) sm[ve[x][i]]+=k-a[x];
35             a[x]=k;
36         }else{
37             scanf("%d",&x); int ed=ve[x].size()-1; ll res=0;
38             rep(i,0,ed) res+=sm[ve[x][i]]*miu[ve[x][i]];
39             printf("%lld\n",res);
40         }
41     }
42     return 0;
43 }
51nod1678

 

 

51nod1406 與查詢

比較巧妙的DP,具體見程式碼。注意這題需要快速讀入與輸出。

$O(A\log A)$

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9 const int N=1000010;
10 int n,x,mx,ww[30],f[N];
11 
12 inline void rd(int &x){
13     x=0; char ch=getchar();
14     while (ch<'0' || ch>'9') ch=getchar();
15     while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
16 }
17 
18 inline void pr(int x){
19     int tot=0;
20     if (!x) { putchar('0'); return; }
21     while (x) ww[++tot]=x%10,x/=10;
22     while (tot) putchar(ww[tot--]+'0');
23 }
24 
25 int main(){
26     rd(n);
27     rep(i,1,n) rd(x),mx=max(mx,x),f[x]++;
28     for (int i=1; i<=mx; i<<=1)
29         for (int j=mx; j; j--) if (i&j) f[j-i]+=f[j];
30     rep(i,0,1000000) pr(f[i]),putchar('\n');
31     return 0;
32 }
51nod1406

 

51nod1407 與與與與

考慮容斥,求“相鄰後至少k位為1”的方案數f(x),答案就是$2^{f(x)}-1$。求f(x)就是上一道題。

$O(A\log A)$

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9 const int N=1000010,mod=1e9+7;
10 int n,x,mx,ans,f[N];
11 
12 int ksm(int a,int b){
13     int res=1;
14     for (; b; a=1ll*a*a%mod,b>>=1)
15         if (b & 1) res=1ll*res*a%mod;
16     return res;
17 }
18 
19 int Cnt(int x){
20     int res=1;
21     for (; x; x>>=1) if (x&1) res=-res;
22     return res;
23 }
24 
25 int main(){
26     while (~scanf("%d",&n)){
27         rep(i,0,mx) f[i]=0; mx=ans=0;
28         rep(i,1,n) scanf("%d",&x),mx=max(mx,x),f[x]++;
29         for (int i=1; i<=mx; i<<=1)
30             for (int j=mx; j; j--) if (i&j) f[j-i]+=f[j];
31         rep(i,0,mx) ans=(ans+Cnt(i)*(ksm(2,f[i])-1))%mod;
32         printf("%d\n",(ans+mod)%mod);
33     }
34     return 0;
35 }
51nod1407

 

51nod1667 概率好題

好題。https://blog.csdn.net/samjia2000/article/details/53025218

$O(2^{k1+k2})$

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 using namespace std;
 6 
 7 const int N=20,mod=1e9+7;
 8 int T,n,m,l,r,s,sm,ans1,ans2,ans3,len[N];
 9 
10 int ksm(int a,int b){
11     int res=1;
12     for (; b; a=1ll*a*a%mod,b>>=1)
13         if (b & 1) res=1ll*res*a%mod;
14     return res;
15 }
16 
17 int C(int n,int m){
18     if (n<m) return 0;
19     int res=1;
20     rep(i,1,m) res=1ll*res*(n-m+i)%mod*ksm(i,mod-2)%mod;
21     return res;
22 }
23 
24 void dfs(int x,int t,int d){
25     if (x>n+m){
26         ans1=(ans1+1ll*t*C(sm-d+n+m-1,n+m)+mod)%mod;
27         ans2=(ans2+1ll*t*C(sm-d+n+m-1,n+m-1)+mod)%mod;
28         return;
29     }
30     dfs(x+1,t,d); dfs(x+1,-t,d+len[x]);
31 }
32 
33 int main(){
34     for (scanf("%d",&T); T--; ){
35         scanf("%d",&n); s=1; sm=ans1=ans2=0;
36         rep(i,1,n) scanf("%d%d",&l,&r),sm+=r,len[i]=r-l+1,s=1ll*s*len[i]%mod;
37         scanf("%d",&m);
38         rep(i,1,m) scanf("%d%d",&l,&r),sm-=l,len[i+n]=r-l+1,s=1ll*s*len[i+n]%mod;
39         dfs(1,1,0); ans3=(1ll*s-ans1-ans2+mod+mod)%mod; s=ksm(s,mod-2);
40         ans1=1ll*ans1*s%mod; ans2=1ll*ans2*s%mod; ans3=1ll*ans3*s%mod;
41         printf("%d %d %d\n",ans1,ans2,ans3);
42     }
43     return 0;
44 }
51nod1667