[二分] cf 768B Code For 1

来源:互联网 发布:个人博客整站源码 编辑:程序博客网 时间:2024/05/22 14:23

[二分] cf 768B Code For 1

@(ACM题目)[二分图]

比赛时各种zz,搞了2h才搞出来(ノಠ益ಠ)ノ彡┻━┻,最后用的是递归求解。之后看了别人的才发现很简洁的规律(二进制无敌!进制无敌!无敌!无敌!敌!)。

以后需要注意:与复制有关的要考虑二进制

题意

将一个数n拆成数列n2, nmod2, n2,重复对数列中大于1的数字进行同样的拆操作,直到整个数列变成01串。问最后得到的数列中,[l, r]之间有多少个1

题意转换

拆的操作即为n>>1,n&1,n>>1,其中n&1即n在二进制下的末位,而去掉这个末位得到的就是n>>1。也就是要将n的二进制表示中的最低位放在中间,剩余的二进制位在这个最低位左右各放一份,继续进行拆操作。
设数字n对应的二进制表示为abcde,其中a、b、c、d、e为0或1(如22表示为10110),则对应“拆”的过程为:
- 以e为中心:abcd, e, abcd
- 以d为中心:abc, d, abc, e, abc, d, abc
- 以c为中心:ab, c, ab, d, ab, c, ab, e, ab, c, ab, d, ab, c, ab
- 以b为中心:a, b, a, c, a, b, a, d, a, b, a, c, a, b, a, e, a, b, a, c, a, b, a, d, a, b, a, c, a, b, a

规律

设n的二进制表示为a1a2...am,则最终得到的字符串中第i位的数字为alog2(lowbit(i))

#include<iostream>#include<cstdio>#include <cstring>#include<cmath>#include<cstdlib>#include<climits>#include<algorithm>#include<vector>#include<map>#include<set>#include<list>#include<stack>using namespace std;typedef long long LL;const int maxn = 55;int bn[maxn];int main(){    LL n, l, r;    cin>>n>>l>>r;    for(int i = log2(n); i >= 0; i--)    {        bn[i] = n&1;        n >>= 1;    }    int res = 0;    for(LL i = l; i <= r; i++) res += bn[(int)log2(i&-i)];    cout<<res<<endl;    return 0;}

递归程序

f(i)代表第1到第i位有多少个1,递归地算。

#include<iostream>#include<cstdio>#include <cstring>#include<cmath>#include<cstdlib>#include<climits>#include<algorithm>#include<vector>#include<map>#include<set>#include<list>#include<stack>using namespace std;typedef long long LL;const int maxn = 55;bool ck[maxn];map<LL, int> mp;LL f(LL n){    LL lb = n&(-n);    if(n==0) return 0;    if(n==lb) return ck[mp[n]+1]+f(n-1);    else if(((n+1)&(-n-1))==n+1)        return ck[mp[n+1]]+2*f(n>>1);    return f(n-lb)+f(lb);}int main(){    LL cur = 1;    for(int i = 0; i <= 51; i++)    {        mp[cur] = i;        cur<<=1;    }    LL n, l, r, res = 0;    cin>>n>>l>>r;    LL nn = n;    int cnt = 0;    while(nn)    {        cnt++;        nn>>=1;    }    nn=n;    while(nn)    {        ck[cnt--] = nn&1;        nn>>=1;    }    cout<<f(r)-f(l-1)<<endl;    return 0;}
0 0
原创粉丝点击