2017之江学院校赛 qwb与支教 容斥+二分

scription
qwb同时也是是之江学院的志愿者,暑期要前往周边地区支教,为了提高小学生的数学水平。她把小学生排成一排,从左至右从1开始依次往上报数。

玩完一轮后,他发现这个游戏太简单了。于是他选了3个不同的数x,y,z;从1依次往上开始报数,遇到x的倍数、y的倍数或z的倍数就跳过。如果x=2,y=3,z=5;第一名小学生报1,第2名得跳过2、3、4、5、6,报7;第3名得跳过8、9、10,报11。

那么问题来了,请你来计算,第N名学生报的数字是多少?

Input
多组测试数据,处理到文件结束。(测试数据数量<=8000)

每个测试例一行,每行有四个整数x,y,z,N。( 2≤x,y,z≤107,1≤N≤1017)。

Output
对于每个测试例,输出第N名学生所报的数字,每个报数占一行。
Sample Input
2 3 5 2
6 2 4 10000
Sample Output
7
19999
HINT

昨晚普遍状态:想法蜜汁快,然后迷之卡点,调试贼久,然后迷之ac。。。。
然后罚时爆炸- -。。还是觉得要多打打这种 不然心态稳不住

离散没学好 卡贼久。。。一个原因是我一开始只记得定理
三个互质的 x,y,z 才能这样这样容斥。后来想到三个不互质的用最小公倍数再容斥就好。

#include 
using namespace std;
typedef long long ll;


ll gcd(ll a,ll b)
{
    return (b==0)?a:gcd(b,a%b);
}

ll lcm(ll a,ll b)
{
    return a/gcd(a,b)*b;
}

ll xx,yy,zz,hh;

long long x,y,z;
ll pan(ll mm)
{
    ll res=0;
    res=mm/x+mm/y+mm/z-mm/xx-mm/yy-mm/zz+mm/hh;
    return mm-res;
}

int main()
{
    long long n;
    while(scanf("%lld%lld%lld%lld",&x,&y,&z,&n)!=EOF)
    {
    if(n==1)
    {
        printf("1\n");
        continue;
    }
    xx=lcm(x,y);
    yy=lcm(x,z);
    zz=lcm(y,z);
    hh=lcm(lcm(xx,yy),zz);

    ll l=1,r=1e18;//右边界开小了
    ll res=0;
    while(l<=r){
        ll mid=(l+r)>>1;
        if(pan(mid)>n)
        {
            r=mid-1;
        }
        else if(pan(mid)1;
        }
        else
        {
            res=mid;
            r=mid-1;
        }
    }
    printf("%lld\n",res );
    }
}
/**************************************************************
    Problem: 1481
    User: ZJC2017Final378
    Language: C++
    Result: Accepted
    Time:64 ms
    Memory:1712 kb
****************************************************************/

你可能感兴趣的:(容斥原理)