hdoj 5358 First One

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

一开始一直以为是一道数学题,在找有什么规律化简Log2(S(i,j)),结束了以后才造  ⌊log2(x)⌋ 即表示x的二进制的最高位。

总结了以下几点:

1、直接暴力肯定会T,status上基本上都是T

2、⌊log2(S(i,j))⌋ +1,表示S(i,j)用二进制表示的位数

3、S(i,j)可以由S(j) - S(i) 表示

4、用尺取法进行枚举区间在区间[2^(k-1),2^k]内的[ i, [ l, r ]],方法如下

1)固定 i

2)找到大于等于L的第一个 l,和大于等于R的第一个 r+1(即 r 小于 R )

3)排除不符合条件的 l 和 r

3)计算 ( i + j ) 的值

4)改变 i 值重复以上过程

#include<stdio.h>
#include<math.h>
const int MAXN = 100010;
int T;
int n;
long long a[MAXN], sum[MAXN];

long long solve(long long L, long long R){

    long long ans = 0;
    int l, r;
    l = 1; r = 0;
    //定义两个标记,l和r
    for( int i = 1; i <= n; ++i){
        if( l < i )
            l = i;
        if( r + 1 < i)
            r = i - 1;
        while( l <= n && sum[l] - sum[i-1] < L)
            l++;
        while( r+1 <= n && sum[r+1] - sum[i-1] < R )
            r++;
        //循环,使得 sum(i,l) >= L  sum(i,r) < R,即上界和下界
        if( l > r)
            continue;
        if( sum[r]-sum[i-1] < L || sum[r] - sum[i-1] >= R )
            continue;
        if( sum[l]-sum[i-1] < L || sum[l] - sum[i-1] >= R )
            continue;
        //排除不符合条件的情况
        ans += ( long long )(r-l+1)*i+(long long )(r-l+1)*(r+l)/2;
        //求(i,l)到(i,r) 的 i+j 和
    }
    return ans;

}
int main(){
    long long ans;
    scanf("%d", &T);
    while(T--){
        ans = 0;
        scanf("%d", &n);
        sum[0] = 0;
        for( int i = 1; i <= n; ++i){
            scanf("%I64d",&a[i]);
            sum[i] = sum[i-1] + a[i];
        }
        //数据读取,sum存储从第一个元素到第i个元素的和
        for( int k = 1; k <= 34; ++k){
            ans += (long long )k * solve(pow(2,k-1),pow(2,k));
        }
        ans += solve(0,1);
        //加上[0,1)区间
        printf("%I64d\n",ans);
    }
}

代码学习了:http://blog.csdn.net/zjck1995/article/details/47321881

ACM毕竟是编程竞赛,数学问题也要结合计算机相关知识进行考虑。

时间: 2024-10-17 15:50:56

hdoj 5358 First One的相关文章

HDOJ 5358 First One 暴力

?log2S(i,j)?+1 就是S(i,j) 的二进制位数..... 枚举二进制的每一位数,计算相应的权值 具体作法就是对每个二进制位数 i ,扫一遍数组,对每个数 j 维护一个L,R 表示以该数为左端点,右端点可以在L~R的范围,这个区间内的值 加起来有 i 位二进制位数,那么这个数对答案的贡献为  设: dur = (R-L+1)  贡献值:  dur*j+(R+L)*dur/2 C++秒T , G++ 1.3s ac First One Time Limit: 4000/2000 MS

【HDOJ】4328 Cut the cake

将原问题转化为求完全由1组成的最大子矩阵.挺经典的通过dp将n^3转化为n^2. 1 /* 4328 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector>

hdu 5358 First One (尺取法)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5358 题意: 分析:首先要知道[log2(x)]+1代表x的位数,而且根据题意不会超过35,那么枚举位数i:1~35.对于每一位i找到区间[x,y],使得S(x,y)的二进制表示的位数等于i,此时的贡献为i*(x+y).那么对于每一个i,怎么找出所有符合条件的区间[x,y]?1~n枚举起点x,那么y会在一段范围[l,r]内满足条件.下次x变成x+1,即起点x向右移位,那么现在要找的y的区间为[l',r'

POJ Xiangqi 4001 &amp;&amp; HDOJ 4121 Xiangqi

题目链接(POJ):http://poj.org/problem?id=4001 题目链接(HDOJ):http://acm.hdu.edu.cn/showproblem.php?pid=4121 Xiangqi Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1108   Accepted: 299 Description Xiangqi is one of the most popular two-player boa

【HDOJ】4956 Poor Hanamichi

基本数学题一道,看错位数,当成大数减做了,而且还把方向看反了.所求为最接近l的值. 1 #include <cstdio> 2 3 int f(__int64 x) { 4 int i, sum; 5 6 i = sum = 0; 7 while (x) { 8 if (i & 1) 9 sum -= x%10; 10 else 11 sum += x%10; 12 ++i; 13 x/=10; 14 } 15 return sum; 16 } 17 18 int main() { 1

HDOJ 4901 The Romantic Hero

DP....扫两遍组合起来 The Romantic Hero Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 547    Accepted Submission(s): 217 Problem Description There is an old country and the king fell in love with a

【HDOJ】1099 Lottery

题意超难懂,实则一道概率论的题目.求P(n).P(n) = n*(1+1/2+1/3+1/4+...+1/n).结果如果可以除尽则表示为整数,否则表示为假分数. 1 #include <cstdio> 2 #include <cstring> 3 4 #define MAXN 25 5 6 __int64 buf[MAXN]; 7 8 __int64 gcd(__int64 a, __int64 b) { 9 if (b == 0) return a; 10 else return

【HDOJ】2844 Coins

完全背包. 1 #include <stdio.h> 2 #include <string.h> 3 4 int a[105], c[105]; 5 int n, m; 6 int dp[100005]; 7 8 int mymax(int a, int b) { 9 return a>b ? a:b; 10 } 11 12 void CompletePack(int c) { 13 int i; 14 15 for (i=c; i<=m; ++i) 16 dp[i]

HDOJ 3790 双权值Dijkstra

1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <cstring> 5 using namespace std; 6 7 const int INF = 1000000; 8 const int MAXSIZE = 1005; 9 10 int map[MAXSIZE][MAXSIZE]; 11 int price[MAXSIZE][MAXSIZE]; 1