中国剩余定理,求解符合若干个x%a[i]≡b[i]的式子的答案x,其中a两两互质(模板中求出的最小的非负整数解)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[3],b[3]={23,28,33}; void exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1;y=0; return; } exgcd(b,a%b,x,y); int tmp=x; x=y; y=tmp-a/b*y; } int crt(int n) { int i,tmp,ans=0,lcm=1,x,y; for (i=0;i<n;++i) lcm*=b[i]; for (i=0;i<n;++i) { tmp=lcm/b[i]; exgcd(tmp,b[i],x,y); x=(x%b[i]+b[i])%b[i]; ans=(ans+tmp*x*a[i])%lcm; } return (ans+lcm)%lcm; } int main() { int p,e,i,d; int cnt=0,ans; while (scanf("%d%d%d%d",&p,&e,&i,&d)!=EOF) { if (p==-1) break; a[0]=p; a[1]=e; a[2]=i; ans=crt(3); if (ans<=d) ans+=21252; cnt++; printf("Case %d: the next triple peak occurs in %d days. ",cnt,ans-d); } return 0; }
扩展中国剩余定理,求解符合若干个x%m[i]≡r[i]的式子的答案x,其中m不一定两两互质(不会证明,我就记个模板。。)
#include<cstdio> #include<cstring> #include<algorithm> #define maxn 15 using namespace std; typedef long long ll; ll a[maxn],r[maxn]; ll exgcd(ll a,ll b,ll &x,ll &y) { if (b==0) { x=1;y=0; return a; } ll gcd=exgcd(b,a%b,x,y); ll tmp=x; x=y; y=tmp-a/b*y; return gcd; } ll ex_crt(int n,ll lim) { ll M=a[1],R=r[1],x,y,d; for (int i=2;i<=n;i++) { d=exgcd(M,a[i],x,y); if ((R-r[i])%d) return 0; x=(R-r[i])/d*x%a[i]; R-=M*x; M=M/d*a[i]; R%=M; } ll ans=(R%M+M)%M; if (ans==0) return (lim-ans)/M; if (ans>lim) return 0; return (lim-ans)/M+1; } int main() { int n,lim,i,T; scanf("%d",&T); while (T--) { scanf("%d%d",&lim,&n); for (i=1;i<=n;i++) scanf("%lld",&a[i]); for (i=1;i<=n;i++) scanf("%lld",&r[i]); printf("%lld ",ex_crt(n,lim)); } return 0; }
先求出1e6内的欧拉函数,求出它的前缀和,二分查找分母x,然后从0至x枚举直到找到答案。
#include<cstdio> #include<cstring> #include<algorithm> #define maxn 1000005 using namespace std; typedef long long ll; ll phi[maxn],sum[maxn],ans1,ans2; const int lim=1000000; int gcd(int x,int y) { if (y==0) return x; return gcd(y,x%y); } void prework() { int i,j; phi[1]=2; for (i=2;i<=lim;i++) { if (!phi[i]) { for (j=i;j<=lim;j+=i) { if (!phi[j]) phi[j]=j; phi[j]=phi[j]/i*(i-1); } } } for (i=1;i<=lim;i++) sum[i]=sum[i-1]+phi[i]; } void work(ll x) { int i,l=0,r=lim,mid; while (l<=r) { mid=(l+r)>>1; if (sum[mid]<x) l=mid+1; else r=mid-1; } /*l=lower_bound(sum+1,sum+lim+1,x)-sum; //另一种替代二分的方法 */ x-=sum[l-1]; for (i=0;i<=l;i++) { if (gcd(i,l)==1) x--; if (x==0) { ans1=i;ans2=l; return; } } } int main() { ll n; int i,T; prework(); while (scanf("%lld",&n)!=EOF && n!=0) { work(n); printf("%d/%d ",ans1,ans2); } return 0; }
D POJ 3904
E HDU 2588
F HDU 4704
题意:(我没看懂题目)求N的划分数。
答案显然为2N-1,由于N很大(10100000),这里要使用费马小定理,即当p是一个素数且与a互质时,ap-1%p≡1,
于是令N=N%(mod-1),快速幂求2N-1即可(注意考虑求出来的N为0的情况)
#include<cstdio> #include<cstring> #include<algorithm> #define mod 1000000007 #define maxn 100005 using namespace std; typedef long long ll; char s[maxn]; int pow(int x,int k) { int now=x,re=1; while (k) { if (k&1) re=(1ll*re*now)%mod; k>>=1; now=(1ll*now*now)%mod; } return re; } int main() { int i,len,x; while (scanf("%s",s)!=EOF) { x=0; len=strlen(s); for (i=0;i<len;i++) { x=(1ll*x*10+s[i]-'0')%(mod-1);//费马小定理 } x=(x-1+mod-1)%(mod-1); printf("%d ",pow(2,x)); } return 0; }
H POJ 1811
先用Miller_Rabin算法进行素数判断,再用Pollard_rho分解因子。(模板题)
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<time.h> #include<map> using namespace std; typedef long long ll; const int rep=50; map<ll,int>mp; 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; } ll gcd(ll a,ll b) { if (b==0) return a; else return gcd(b,a%b); } ll Pollard_Rho(ll n, int c) { ll i=1,k=2,x=rand()%(n-1)+1,y=x; while (1) { i++; x=(qmul(x,x,n)+c)%n; ll p=gcd((y-x+n)%n,n); if (p!=1 && p!=n) return p; if (y==x) return n; if (i==k) { y=x; k<<=1; } } } void Find(ll n, ll c) { if (n==1) return; if (MR(n,rep)) { mp[n]++; return; } ll p=n; while (p>=n) p=Pollard_Rho(p,c--); Find(p,c); Find(n/p,c); } int main() { ll n; int i,T; srand(time(NULL)); scanf("%d",&T); while (T--) { scanf("%lld",&n); mp.clear(); if (MR(n,rep)) printf("Prime "); else { Find(n,rand()%(n-1)+1); map<ll,int>::iterator it=mp.begin(); printf("%lld ",it->first); } } return 0; }