51nod 1674 区间的价值V2(思维+拆位+尺取法)
最近被四区题暴虐。。。
题意:lyk拥有一个区间。
它规定一个区间的价值为这个区间中所有数and起来的值与这个区间所有数or起来的值的乘积。
例如3个数2,3,6。它们and起来的值为2,or起来的值为7,这个区间对答案的贡献为2*7=14。
现在lyk有一个n个数的序列,它想知道所有n*(n+1)/2个区间的贡献的和对1000000007取模后的结果是多少。
区间的and值和区间的or值相乘,实际上等于将and值分解为2的幂次和的形式与or值分解成2的幂次和的形式相乘。
所以对于同一段区间来说,是可以按位来统计的。
首先将数列按位分解成32个位数列。
枚举区间的左端点,,区间的and值要对答案有贡献必须为1,随着右端点右移,and值为不递增的,而区间的or值要对答案有贡献必须为1,随着右端点右移,or值为不递减的。
找到这两个满足条件的最大区间的交集,即可统计出这段区间对答案的贡献。
先用尺取法进行预处理,再依此统计答案。
时间复杂度O(n*loga*loga)。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <bitset> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-8 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; inline int Scan() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } inline void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=100005; //Code begin... int R[32][N], L[32][N], n, mod[65]; LL ans; bool wei[32][N]; void init(){ mod[0]=1; FOR(i,1,64) mod[i]=(mod[i-1]<<1)%MOD; FO(i,0,32) { int l=1, r=1; while (l<=n) { if (!wei[i][l]) L[i][l]=0; else { r=max(r,l); while (r<n&&wei[i][r+1]) ++r; L[i][l]=r; } ++l; } } FO(i,0,32) { int l=1, r=1; while (l<=n) { if (wei[i][l]) R[i][l]=l; else { r=max(l,r); while (r<=n&&!wei[i][r]) ++r; R[i][l]=r; } ++l; } } } void sol(){ FO(i,0,32) FOR(j,1,n) { if (!wei[i][j]) continue; FO(k,0,32) { if (R[k][j]>L[i][j]) continue; ans=(ans+(LL)(L[i][j]-R[k][j]+1)*mod[i+k])%MOD; } } } int main () { int x; n=Scan(); FOR(i,1,n) { x=Scan(); FO(j,0,32) wei[j][i]=x%2, x/=2; } init(); sol(); printf("%lld\n",ans); return 0; }