(数论菜鸡,全程划水)
B POJ 1061
这题,一眼看出是考扩展欧几里得,然而搞了半天没搞出来,WA了一片。。最后心态爆炸。。。(代码就那么短)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> typedef long long ll; ll exgcd(ll a,ll b,ll & x,ll & y) { if (b==0) { x=1;y=0; return a; } ll g=exgcd(b,a%b,x,y); ll t=x; x=y; y=t-a/b*y; return g; } int main() { ll xx,yy,m,n,L,x,y,a,b,c,g,t; while (scanf("%lld%lld%lld%lld%lld",&xx,&yy,&m,&n,&L)!=EOF) { a=n-m; b=L; c=xx-yy; g=exgcd(a,b,x,y); if (c%g!=0) printf("Impossible "); else { x=x*c/g; //x+b/g*t为通解 t=(-x)*g/b; x=x+b/g*t; if (x<0) x+=b/g; printf("%lld ",x); } } return 0; }
D HDU 4135
求区间内与N互质数的个数
由于区间范围很大(1015),for循环一个个判断是不是质数的方法不可行。于是想到先求区间内不与N互质的数的数量。先对N分解质因子,应用容斥原理就可以算出区间内与N不互质的数的数量。
应用容斥原理有几种实现方法,这里用的是位运算的方法。(感觉比较简洁好理解)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #define maxn 100005 int not_prime[maxn],prime[maxn],cnt; int q[maxn<<1],l; void pri(int n) { int i,j; for (i=2;i<=n;i++) { if (!not_prime[i]) prime[++cnt]=i; for (j=1;j<=cnt && i*prime[j]<=n;j++) { not_prime[i*prime[j]]=1; if (i%prime[j]==0) break; } } } void find(int n) { for (int i=1;i<=cnt && n>prime[i];i++) if (n%prime[i]==0) { while (n%prime[i]==0) n/=prime[i]; q[l++]=prime[i]; } if (n!=1) q[l++]=n; } long long work(long long x) { int i,j,tot=0; long long tmp,res=0; for (i=1;i<(1<<l);i++) { tmp=1;tot=0; for (j=0;j<l;j++) if ((i>>j)&1) { tot++; tmp*=q[j]; } if (tot&1) res+=x/tmp; else res-=x/tmp; } return x-res; } int main() { int i,k,t,n; long long a,b; pri(100000); scanf("%d",&t); for (k=1;k<=t;k++) { scanf("%lld%lld%d",&a,&b,&n); l=0; find(n); printf("Case #%d: %lld ",k,work(b)-work(a-1)); } return 0; }
一个求逆元+快速幂+等比数列求和的问题。先计算出0-k-1项的和,就是首项a1,公比q就是(b/a)k。然后就是等比数列求和(anq-a1)/(q-1),注意要特判q=1的情况。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #define mod 1000000009 #define maxn 100005 typedef long long ll; char s[maxn]; ll pow(ll x,ll k) { ll re=1; while (k) { if (k&1) re=re*x%mod; k>>=1; x=x*x%mod; } return re; } int main() { int i,n,k,now; ll a,b,q,inva,invq,ans,tmp; while (scanf("%d%lld%lld%d%s",&n,&a,&b,&k,s)!=EOF) { ans=0; for (i=0;i<k;i++) { tmp=pow(a,n-i)*pow(b,i)%mod; if (s[i]=='-') ans=(ans-tmp+mod)%mod; else ans=(ans+tmp)%mod; } now=(n+1)/k; inva=pow(a,mod-2); q=pow(inva,k)*pow(b,k)%mod; if (q==1) { ans=ans*now%mod; } else { invq=pow(q-1,mod-2); ans=ans*(pow(q,now)-1)%mod*invq%mod; } printf("%lld ",ans); } return 0; }
G HDU 6608
先用Miller_Rabin判素数找出q,
由威尔逊定理可知(p-2)!≡1 (mod p),而当q小于p-2时,有k*q!=(p-2)!(k=(p-2)*(p-1)......*(q+1))。
因此只要求出k的逆元,k的逆元就是答案了。
注意需要使用快速乘。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<time.h> #define maxn 1000005 using namespace std; typedef long long ll; ll qmul(ll a,ll b,ll mod) { ll ans=0; a=a%mod; while (b) { if (b&1) ans=(ans+a)%mod; a=(a+a)%mod; b>>=1; } return ans; } ll qpow(ll a,ll b,ll mod) { ll ans=1; a=a%mod; while (b) { if (b&1) ans=qmul(ans,a,mod); a=qmul(a,a,mod); b>>=1; } return ans; } int MR(ll n,int repeat) { if (n==2 || n==3) return 1; int i,j,s=0; ll d=n-1; while (!(d&1)) { s++; d>>=1; } for (i=0;i<repeat;i++) { ll a=rand()%(n-3)+2; ll x=qpow(a,d,n); ll y=0; for (j=0;j<s;j++) { y=qmul(x,x,n); if (y==1 && x!=1 && x!=n-1) return 0; x=y; } if (y!=1) return 0; } return 1; } int main() { int T; ll i,n,now,q; srand(time(NULL)); scanf("%d",&T); while (T--) { scanf("%lld",&n); for (q=n-1;q;q--) if (MR(q,50)) break; now=1; if (q>=n-2) { for (i=q;i>n-2;i--) now=now*i%n; } else { for (i=q+1;i<=n-2;i++) now=qmul(now,qpow(i,n-2,n),n); } printf("%lld ",now); } return 0; }
题意:有n种花,其中第i种花有f[i]支,要从这些盒子中取s支花,问有几种取法。
思路:问题可以看作将s个球放入n个盒子中,第i个盒子中的球不超过f[i]个。
如果没有f的限制,利用隔板法可知有C(s+n-1,n-1)种取法。
当第i个盒子中的球超过f[i]时,此时不合法的方案数为C(s-f[i]-1+n-1,n-1)
当第i,j个盒子中的球分别超过f[i],f[j]时,此时不合法的方案数为C(s-f[i]-1-f[j]-1+n-1,n-1),以此类推。
于是就可使用容斥原理计算方案数了,ans=C(s+n-1,n-1)-ΣC(s-f[i]-1+n-1,n-1)+∑C(s-f[i]-1-f[j]-1+n-1,n-1)-......(-1)s∑C(s-∑(f[i]+1)+n-1,n-1)
这里由于s较大,求组合数使用了Lucas定理,即C(n,m)%p=Lucas(n,m,p)=Lucas(n/p,m/p,p)*C(n%p,m%p,p)%p。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const ll p=1e9+7; ll f[25]; ll qpow(ll x,ll k,ll p) { ll re=1; while (k) { if (k&1) re=re*x%p; k>>=1; x=x*x%p; } return re; } ll get_c(ll n,ll m,ll p) { if (n<m) return 0; if (m>n-m) m=n-m; ll i,s1=1,s2=1; for (i=0;i<m;i++) { s1=s1*(n-i)%p;//n!/(n-m)! s2=s2*(i+1)%p;//m! } return s1*qpow(s2,p-2,p)%p; } ll lucas(ll n,ll m,ll p) { if (m==0) return 1; return lucas(n/p,m/p,p)*get_c(n%p,m%p,p)%p; } ll solve(ll n,ll s,ll p) { ll i,j,ans=0,sign,sum; for (i=0;i<(1<<n);i++) { sign=1; sum=s; for (j=0;j<n;j++) if ((i>>j)&1) { sum=sum-f[j]-1; sign*=-1; } if (sum<0) continue; ans+=sign*lucas(sum+n-1,n-1,p); ans=ans%p; } return (ans+p)%p; } int main() { ll i,n,s; scanf("%lld%lld",&n,&s); for (i=0;i<n;i++) scanf("%lld",&f[i]); printf("%lld ",solve(n,s,p)); return 0; }