poj 2773 Happy 2006

来源:互联网 发布:移动宽带送的网络电视 编辑:程序博客网 时间:2024/05/21 14:44

这是自己的第二道容斥题,也是自己第一道独立完成的容斥题,值得留念。

题意很简单,求与m(1-1000000)互质的第k(1-100000000)个数,做法是容斥+二分+一些优化。

1.对m或k等于1,还有m是素数时做特殊处理。

2.由于k的变化有周期phi[m]的变化,所以使 k = k % phi[m];

3.二分+容斥

#include <cstdio>#include <cstring>#define print(n) printf("%d ",n)typedef long long ll;const int size = 1000010;int prime[size/5],phi[size],np;bool isp[size];void table(void){    memset(isp,true,sizeof(isp));    phi[1] = 1;    for(int i = 2; i < size; i++) {        if(isp[i]) {            prime[np++] = i;            phi[i] = i - 1;        }        int t;        for(int j = 0; j < np && (t = i*prime[j]) <size; j++) {            isp[t] = false;            if(i % prime[j] == 0) {                phi[t] = prime[j]*phi[i];                break;            } else {                phi[t] = (prime[j]-1)*phi[i];            }        }    }}//return the number of relatively primes of n between 1 and nint value,div[20];int fac[20],nfac = 0;;void getvalue(int st,int cur,int goal,int v){    if(cur == goal) {        for(int i = 0; i < goal; i++)            v /= div[i];        value += v;    } else {        for(int i = st; i < nfac; i++) {            div[cur] = fac[i];            getvalue(i+1,cur+1,goal,v);        }    }}int in_ex(int p,int n){    int ans = p;    for(int i = 0; i < nfac; i++) {        value = 0;        getvalue(0,0,i+1,p);        if(i & 1) ans += value;        else ans -= value;    }    return ans;}int gcd(int a,int b){    return b ? gcd(b,a%b) : a;}void debug(void){    for(int i = 1; i < 100; i++)        printf("%d %d %d\n",i,prime[i],phi[i]);}int main(){    int m,k;//    freopen("data.in",)    table();    //  debug();    while(~scanf("%d%d",&m,&k)) {        if(m == 1 || k == 1) {            printf("%d\n",k);            continue;        else if(isp[m]) {            int ans = k/(m-1)*m + k%(m-1);            if(k % (m-1) == 0) ans--;            printf("%d\n",ans);            continue;        }        int extd = k / phi[m];        k %= phi[m];        int t = m;        nfac = 0;        for(int i = 0; i < np; i++) {            if(t % prime[i] == 0) {                while(t % prime[i] == 0)                    t /= prime[i];                fac[nfac++] = prime[i];            }            if(t == 1) break;        }        int low = 0,high = m-1,mid;        while(1) {            mid = (high+low) / 2;;            int v = in_ex(mid,m);            if(v > k)                high = mid - 1;            else if(v < k)                low = mid + 1;            else break;        }        while(gcd(mid,m) != 1) {            mid--;            if(mid <= 0) { /*注意此处*/                mid += m;                extd--;            }        }        printf("%I64d\n",mid+(ll)extd*m);    }    return 0;}


原创粉丝点击