數論基礎
阿新 • • 發佈:2020-08-07
A - Big Number
模擬十進位制的除法
#include<bits/stdc++.h> using namespace std; const int inf=0x3f3f3f3f; const int N=1e5+500; int main(){ string s;int b; while(cin>>s>>b){ int a=0; for(int i=0;i<s.size();i++){ a=a*10+s[i]-'0'; aView Code%=b; } cout<<a<<endl; } // system("pause"); return 0; }
B - Largest prime factor
模擬埃氏篩 篩素數的過程,如果遇到素數,那麼將他的倍數標記成這個素數的標記號。n logn logn
#include<bits/stdc++.h> using namespace std; const int inf=0x3f3f3f3f; const intView CodeN=1e6+500; const int maxn=1e6+500; typedef long long ll; int num[N]; void work(){ memset(num,0,sizeof num); num[1]=0; int tot=1; for(int i=2;i<maxn;i++){ if(!num[i]){ num[i]=tot; for(int j=2;j*i<maxn;j++){ num[j*i]=tot; } tot++; } } } int main(){ work(); int n; while(~scanf("%d",&n)){ printf("%d\n",num[n]); } // system("pause"); return 0; }
C - A/B
費馬小定理,素數模的x逆元為 x的p-2次方
#include<bits/stdc++.h> using namespace std; const int inf=0x3f3f3f3f; const int N=1e6+500; const int maxn=1e6+500; typedef long long ll; const ll mod=9973; ll quickPower(ll a, ll b,ll m) { //計算a的b次方 ll ans = 1; ll base = a; while (b) { if (b & 1) { ans *= base; ans %= m; } base *= base; base %= m; b >>= 1; //注意是b>>=1 not b>>1 } return ans; } int main(){ int t;cin>>t; while(t--){ ll n,b; cin>>n>>b; n%=mod; ll xb= quickPower(b,mod-2,mod)%mod; cout<<((n*xb)%mod)<<endl; } // system("pause"); return 0; }View Code
E - Bi-shoe and Phi-shoe
對於每一個數,查詢一個尤拉函式大於等於他的數。
先一遍線性篩尤拉函式,從小到大掃一遍,對於每一個數的尤拉函式,把每一個小於當前尤拉函式,且未被標記的標記為當前值,保證結果最小。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int N=1e6+5; const int maxn=1e6+5; int num[N],phi[N]; int get_ephi(int n) { int m = int(sqrt(n + 0.5)); int ans = n; for (int i = 2; i <= m; i++) { if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0) n /= i; } } if (n > 1) ans = ans / n * (n - 1); return ans; } void phi_table(int n) { for (int i = 2; i <= n; i++) phi[i] = 0; phi[1] = 1; for (int i = 2; i <= n; i++) if (!phi[i]) for (int j = i; j <= n; j += i) { if (!phi[j]) phi[j] = j; phi[j] = phi[j] / i * (i - 1); } } // struct node // { // int key,index; // }a[N]; // bool cmp(node a,node b){ // if(a.key!=b.key)return a.key<b.key; // else return a.index<b.index; // } // int check(int x){ // int l=2,r=maxn-1,ans; // while(l<=r){ // int mid=(l+r)>>1; // if(a[mid].key>=x)ans=mid,r=mid-1; // else l=mid+1; // } // return a[ans].index; // } void work(){ phi_table(maxn-1); memset(num,0,sizeof num); for(int i=2;i<maxn;i++){ int xi=phi[i]; while(!num[xi]){ num[xi--]=i; } } // for(int i=2;i<maxn;i++){ // a[i].key=fx[i];a[i].index=i; // } // sort(a+2,a+maxn,cmp); // for(int i=1;i<maxn;i++){ // int tt=check(i); // num[i]=tt; // } } int main(){ int cas=0; work(); int t;cin>>t; while(t--){ int n;cin>>n; ll sum=0; for(int i=1;i<=n;i++){ int a;cin>>a; sum+=num[a]; } printf("Case %d: %lld Xukha\n",++cas,sum); } // system("pause"); return 0; }View Code
F - The Embarrassed Cryptographer
預處理素數,a模擬字串除法,但取餘很耗時間,因此三位相加,然後取餘。
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> // #include<algorithm> #include<vector> // #include<bits/stdc++.h> using namespace std; #define pb push_back const int maxn=1e6+10; typedef long long ll; // int prime[maxn]; bool isprime[maxn]; int cnt=0; char s[120]; int check(int x){ int sum=0; int len=strlen(s); for(int i=0;i<len;i+=3){ int tt=0; for(int j=i;j<i+3&&j<len;j++){ sum*=10; tt=tt*10+s[j]-'0'; } sum+=tt; sum%=x; } sum%=x; if(sum==0)return 1; return 0; } int prime[maxn+50]; int visit[maxn+50]; void make_prime(){ memset(visit,0,sizeof visit); memset(prime, 0,sizeof prime); for (int i = 2;i <= maxn; i++) { if (!visit[i]) { prime[++prime[0]] = i; //紀錄素數, 這個prime[0] 相當於 cnt,用來計數 } for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) { visit[i*prime[j]] = 1; if (i % prime[j] == 0) { break; } } } } int main(){ make_prime(); int L; while(~scanf("%s %d",s,&L)){ if(s[0]=='0'&&L==0)break; bool flag=1; for(int p=1;prime[p]<L;p++){ if(check(prime[p])){ printf("BAD %d\n",prime[p]); flag=0; break; } } if(flag)puts("GOOD"); } // system("pause"); return 0; }View Code
G - Who Gets the Most Candies?
求約數直接預處理,線段樹模擬佇列刪除元素,
應該先-1再取模+1 防止模為0的情況。
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> #include<vector> // #include<bits/stdc++.h> using namespace std; typedef long long ll; #define pb push_back const int N=5e5+50; int n,m; struct SEG{ int sum[N*50]; void push_up(int rt){ sum[rt]=sum[(rt<<1)]+sum[rt<<1 | 1]; } #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1 | 1 void build(int l,int r,int rt){ if(l==r){ sum[rt]=1; return; } int mid=(l+r)>>1; build(lson); build(rson); push_up(rt); } int update(int pos,int l,int r,int rt){//更新a到b區間和 if(l==r){ sum[rt]=0; return l; } int mid=(r+l)>>1; int res; if(pos<=sum[rt<<1])res=update(pos,lson); else res=update(pos-sum[rt<<1],rson); push_up(rt); return res; } }seg; int F[N]; void init(){ fill(F,F+N,2); F[1]=1; for(int i=2;i+i<N;i++){ for(int j=2*i;j<N;j+=i){ F[j]++; } } } char name[N][100],maxname[100]; int num[N]; int main(){ init(); int n,k; while(~scanf("%d %d",&n,&k)){ seg.build(1,n,1); for(int i=1;i<=n;i++){ scanf("%s %d",name[i],&num[i]); } int maxvalue=0; for(int i=1;i<=n;i++){ int cur=seg.update(k,1,n,1); // cout<<i<<" "<<name[cur]<<endl; if(F[i]>maxvalue){ maxvalue=F[i]; strcpy(maxname,name[cur]); } if(i==n)break; int tot=seg.sum[1]; int tmp=(abs(num[cur]))%tot; if(num[cur]>=0)k=(k-1+tmp-1+tot)%tot+1; else k=(k-tmp-1+tot)%tot+1; // k=k%tot+1; // if(num[cur]>0) k=(k-1+tmp-1)%tot+1; // else k=((k-1-tmp+tot))%tot+1; } printf("%s %d\n",maxname,maxvalue); } // system("pause"); return 0; }View Code