传送门:http://www.tsinsen.com/ViewGProblem.page?gpid=A1306
思路:来说一下我的傻逼做法。。。
考虑一个性质,设有区间
f[a,b]
如果
a,b
都是类似于
2i
的形式的话,那么
f[a,b]=2∗f[a+34,b4]
这样每次区间长度都会除以
4
,我们递归的做下去直到底层区间长为
但这样复杂度是
O(qlog2w)
的,这样还不够优秀
我在青橙上是过了的,但
bzoj
时限是青橙的一半,我无论怎么优化都无法过去,实际上
clj
当年怒艹标算得到了更优的复杂度
感谢
xiaoyimi
大爷帮我优化常数
不多说,这题在
bz
上过不去感动的我热泪盈眶。。。
UPD:将递归改为非递归,加了些小优化终于在
bz
上卡过去。。。感人至深
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#define C 60
#define lim 5000000
using namespace std;
typedef long long LL;
LL S,Q,c,n,s,ans,f[lim + 2],g[lim + 2];
char *cp=(char *)malloc(10000000);
void in(LL &x)
{
for (;*cp<'0'||*cp>'9';++cp);
for (x=0;*cp>='0'&&*cp<='9';++cp) x=x*10+(*cp)-48;
}
inline void out(LL x)
{
if (x<0) {putchar('-'),out(-x);return ;}
if (!x) return;
out(x/10);
putchar(x%10+48);
}
inline LL get_point(LL x){
//if (x == 1) return 1;
bool v = 1;
while (x > lim){
if (!(x & 1)) v ^= 1,x >>= 1;
else if ((x >> 1)&1) v ^= 1,x = (x + 1)>>1;
else x = (x + 1)>>1;
}
if (!v) return (-f[x]);
return f[x];
}
inline LL get_interval(LL l,LL r){
LL sum = 1;
while (r - l > 1){
if (r <= lim) return (sum * (g[r] - g[l - 1]));
sum <<= 1;
l = (l + 3)>>2; r >>= 2; }
if (r - l + 1 == 1) return get_point(l) * sum;
return (get_point(l) + get_point(r)) * sum;
//if (r - l + 1 == 1) return get_point(l);
//if (r - l + 1 == 2) return (get_point(l) + get_point(r));
//return (get_interval((l + 3) >> 2,r >> 2) << 1);
}
inline void get_init(){
f[1] = 1;
for (register int i = 2;i <= lim; ++i)
if (!(i & 1)) f[i] = -f[i >> 1];
else if ((i >> 1)&1) f[i] = -f[(i + 1) >> 1];
else f[i] = f[(i + 1) >> 1];
g[0] = 0;
for (register int i = 1;i <= lim; ++i) g[i] = g[i - 1] + f[i];
}
int main(){
//cout<<get_point(3)<<endl;
//cout<<get_point(2)<<endl;
//freopen("123.txt","r",stdin);
fread(cp,1,10000000,stdin);
get_init();
in(Q);
while (Q--){
in(c);in(n);
if (c == 1)
{
ans=get_point(n);
if (!ans) putchar('0');
else out(ans);
}
else{
S = 0; s = 0;
//for (i = 0;i <= C; ++i)
//if ((1LL << i) >= n) break;
//i = min(i,(LL)C);
//dfs(1,(1LL << i),1,n);
for (register LL i = C;i >= 0; --i)
if ((1LL << i) & n){
S += get_interval(s + 1,s + (1LL << i));
s += (1LL << i);
}
if (c == 2) {
if (!S) putchar('0');
else if (S > 0) putchar('+');
else putchar('-');
}
else if (c == 3)
{
ans=S;
if (!ans) putchar('0');
else out(ans);
}
}
puts("");
}
return 0;
}
总结:1.二进制相关:二进制分解,线段树,树状数组
(lowbit)
,倍增等等,多想一想
2.