尺度法(简单数学)
要被打死的预编译...
狗头保命
// 解零 暴力
// 解一
/*
尺度法
保证 tp_sum (inferior,superior]
[枚举]一个区间的[左端点],对于一个给定的左端点,因为f(i,j)在给定i的情况下单调,
我们可以用尺举发求得一个区间[l,r],使得区间内的j (l<=j<=r)都瞒住sum(i,j)+1=k;
然后区间(i+j)的和可以表示为 i*(r-l+1) + (r+l)*(r-l+1)/2;[1]
[1]: https://blog.csdn.net/bigbigship/article/details/47343299
*/
// 解二
/*
尺度法
保证 tp_sum (inferior,+inf]
[log2(inferior)+1] + 1 == [log2(inferior<<1)+1] => 累加
//---
所有区间都满足 inferior=0 => ans = n*(n*n+2*n+1)/2 //算个通项
一但[l,r]满足inferior,则[l,r...n]都满足inferior => ans += (n-r+1)*(r+n)/2+(n-r+1)*l
*/
#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef unsigned char uchar;
typedef unsigned int uint;
// #pragma GCC optimize(2)
#define rint register int
#define rchar register char
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define rep_r(i,a,b) for(rint i=a;i<=b;i++)
#define per_r(i,a,b) for(rint i=a;i>=b;i--)
#define maxn 10000
namespace fast{
inline char GET_CHAR(){//读优卡常
static char buf[maxn],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxn,stdin),p1==p2)?EOF:*p1++;
}
template<class T>inline void read(T &x){//读优背一下就OK
x=0;rchar f=0;rchar ch=GET_CHAR();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=GET_CHAR();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=GET_CHAR();}x=f?-x:x;
}
template<class T>inline T min(T &a,T &b){return a<b?a:b;}
template<class T>inline T max(T &a,T &b){return a>b?a:b;}
template<class T>inline T abs(T &a){return a>=0?a:-a;}
template<class T>inline T sgn(T &a){return a>=0?+1:-1;}
template<class T>inline void swap(T &a,T &b){T tp=a;a=b;b=tp;}
template<class T>inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10|'0');// '1' 049(DEC) 0011'0001(BIN)
}
};
//---
// #define TIME
// #define DEBUG
// #define B_S
const int MAX_N=1e5+5;
const int MAX_A=1e5;
ull n,A[MAX_N];
ull total;
#ifdef B_S
ull sum[MAX_N];
inline int log2_int(ull x){//register int
rchar res=0;//register int
while(x>>=1)res++;
return res;
}
ull bad_solution(){
//O(n^2)
ull ans=0;
rep_r(i,1,n) rep_r(j,i+1,n)
ans+=(log2_int(sum[j]-sum[i-1])+1)*(i+j);
// ans<<=1;
// cout<<ans<<endl;
rep_r(i,1,n){
ans+=(log2_int(A[i])+1)*(i<<1);
}
return ans;
}
#endif
#ifndef B_S
ull solution(){
//O(n*log(n))
ull ans=0;
ull inferior=2;
// 特判 log(2,0)=0
ans=n*(n*n+2*n+1)/2;//被[1]强制转换和[2]优先级坑了
#ifdef DEBUG
putchar('*'); fast::write(ans); putchar('\n');
#endif
while(inferior<=total){
//init
rint l,r;//1e5
ull tp_sum;//1e10
l=r=1;tp_sum=A[r];
while(r<=n){
if(tp_sum<inferior){
tp_sum+=A[++r];
}else{
ans+=(n-r+1)*(r+n)/2+(n-r+1)*l;
tp_sum-=A[l++];
}
}
#ifdef DEBUG
putchar('-'); fast::write(ans); putchar('\n');
#endif
inferior<<=1;
}
return ans;
}
#endif
int main(){
#ifdef TIME
clock_t start_time=clock();
#endif
int _;
fast::read(_);
while(_--){
//init
total=0;
fast::read(n);
rep_r(i,1,n)
#ifndef DEBUG
fast::read(A[i]),
#endif
#ifdef DEBUG
A[i]=100000,
#endif
#ifdef B_S
sum[i]=sum[i-1]+A[i];
#endif
#ifndef B_S
total+=A[i];
#endif
#ifdef DEBUG
printf("total: ");fast::write(total);putchar('\n');
#endif
#ifdef B_S
fast::write(bad_solution());putchar('\n');
#endif
#ifndef B_S
fast::write(solution());putchar('\n');
#endif
}
#ifdef TIME
printf("%.2f",(double)(clock()-start_time)/CLOCKS_PER_SEC);
#endif
return 0;
}
本文章使用limfx的vsocde插件快速发布