51nod部分題解
阿新 • • 發佈:2018-11-26
容斥原理
跟容斥沒有關係。首先可以確定的一個結論是:對於任意正整數,有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> 251nod1434#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 }
先把所有壞點按曼哈頓距離排序。
總方案數減去不合法方案的數量,列舉第一次走到的不合法格子(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
簡單莫比烏斯容斥,答案是$\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
比較巧妙的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
考慮容斥,求“相鄰後至少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
好題。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