您的位置:首页 > 其它

这种题应该诸位处理

2015-10-08 11:03 183 查看
HDU 4588 Count The Carries

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4588

求a~b求和在二进制情况下共发生多少次进位。

1、将i转化成二进制,因为每一位只有出现多个1的时候才会产生进位。

2、所以,统计每一位1的个数即可。

3、统计1~b每一位1的个数,1~a-1中1的个数,作差即可。

(对于怎么统计1~n的每一位1的个数,数学好的应该一眼能看出,数学不好的找找规律画画就行,不难的)

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;
const int maxn = 5e4 + 10;
int bit[maxn][35], a[maxn];
long long n;

void change( int k, int p ){
int cnt = 0;
while(p){
bit[k][cnt++] = p&1;
p >>= 1;
}
}

void input(){
scanf("%lld", &n);
memset( bit, 0, sizeof(bit) );
for( int i = 1; i <= n; ++i ){
scanf("%d", &a[i]);
change( i, a[i] );
}
}

void solve(){
long long ans1 = 0;
//与运算
long long k = 1;
for( int i = 0; i < 32; ++i ){
long long cnt1 = 0;
long long tmp = 0;
for( int j = 1; j <= n; ++j ){
while( j <= n && bit[j][i] == 1 ){
cnt1++;
j++;
}
tmp += cnt1*(cnt1+1)/2;
cnt1 = 0;
}
ans1 += tmp * k, k *= 2;
}
//printf("%lld\n", ans1);

//或运算
long long ans2 = 0;
k = 1;
for( int i = 0; i < 32; ++i ){
long long cnt1 = 0;
long long tmp = 0;
for( int j = 1; j <= n; ++j ){
while( j <= n && bit[j][i] == 0 ){
cnt1++;
j++;
}
tmp += cnt1*(cnt1+1)/2;
cnt1 = 0;
}
ans2 += k*(n*(n+1)/2 - tmp), k *= 2;
}
//printf("%lld\n", ans2);

//异或运算
long long ans3 = 0;
k = 1;
for( int i = 0; i < 32; ++i ){
int ji = 0, ou = 0, tmp = 0;
long long res = 0;
for( int j = 1; j <= n; ++j ){
if( bit[j][i] == 1 ){
tmp++;
}
if(tmp%2){
res += ou+1;
ji++;
}else{
res += ji;
ou++;
}
}
ans3 += res * k, k *= 2;
}

long long tot = n*(n+1)/2;
printf(" %.6lf %.6lf %.6lf\n", ans1/(1.0*tot), ans2/(1.0*tot), ans3/(1.0*tot) );
}

int main(){
int T, cas = 1;
scanf("%d", &T);

while(T--){
input();
printf("Case #%d:", cas++);
solve();
}

return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: