数学题(First One,HDU 5358)

来源:互联网 发布:sql2008数据库删除语句 编辑:程序博客网 时间:2024/06/06 02:58

学习一下吧。

参考博客:

http://blog.csdn.net/u013007900/article/details/47323347

http://bestcoder.hdu.edu.cn/blog/2015-multi-university-training-contest-6-solutions-by-zju/

http://www.cnblogs.com/yfceshi/p/6905876.html


首先floor(log(S(i,j)))肯定是不能一个一个算的,因为要O(n^2)。

而且log+floor又使得没有办法合并或递推。

其他什么(i+j)这种项比较好处理,难点就是这个floor(log(S(i,j)))没法用什么公式或技巧快速算、合并、递推。

看了官方题解,floor(log(S(i,j)))的值范围很小,所以可以枚举它。

我们应该抓住特殊的数据(比如特别小),通过更换枚举顺序或替换枚举的量,来完成一些时间复杂度上的优化。


代码

#include<stdio.h>#include<algorithm>using namespace std;typedef long long ll;const int maxn = 100010;int n;int a[maxn];ll s[maxn];ll Pow[40];void init(){    Pow[0]=0;    Pow[1]=2;    for(int i=2;i<=36;i++) Pow[i]=Pow[i-1]<<1;}void solve(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d",a+i);        s[i]=s[i-1]+a[i];    }    ll ans=0;    for(int k=1;k<=35;k++)    {        int l=1,r=1;        ll tp=0;        for(int i=1;i<=n;i++)        {            l=max(l,i);            while(l<=n&&s[l]-s[i-1]<Pow[k-1]) l++;            while(r<=n&&s[r]-s[i-1]<Pow[k]) r++;            if(l<r) tp+=1ll*(r-l)*i+1ll*(l+r-1)*(r-l)/2;        }        ans+=tp*k;    }    printf("%lld\n",ans);}int main(){    init();    int T;    scanf("%d",&T);    while(T--) solve();    return 0;}