题目描述:
样例:
input1:
3 2 1
1 2 3
2 2
1 3
output1:
1
6
input2:
3 2 2
1 2 3
2 2
1 3
output2:
1
4
input3:
3 2 3
1 2 3
2 2
1 3
output3:
0
3
数据范围与约定:
标签:乱搞
出题人说这是签到题,那我没做出来是不是该退役了?
注意到左端点不变时区间的按位与值最多会变化\(log\)次。
从右往左枚举左端点,记录一个nxt数组表示下一次出现变化的位置在哪里。
出现变化时判一下是否整除,若整除则区间方案数+1
将询问离线,左端点扫到询问的左端点时求一个区间和即可。
奇奇怪怪的复杂度,好像是\(O(n \log n \log a_i +q \log n)\)
毒瘤出题人卡常数……
代码:
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define rep(i,x,y) for (register int i=(x);i<=(y);++i)
#define drep(i,x,y) for (register int i=(x);i>=(y);--i)
#define sz 100010
typedef long long ll;
template<typename T>
inline void read(T& t)
{
t=0;char f=0,ch=getchar();
double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.')
{
ch=getchar();
while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();
}
t=(f?-t:t);
}
template<typename T,typename... Args>
inline void read(T& t,Args&... args){read(t); read(args...);}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.txt","r",stdin);
#endif
}
}
using namespace my_std;
int n,Q,K;
struct hh{int pos,r,id;}q[sz*5];
inline bool cmp(const hh &x,const hh &y){return x.pos>y.pos;}
int a[sz];
ll ans[sz*5];
#define LB(x) ((x)&(-(x)))
ll sum1[sz],sum2[sz];
inline void add(int x,ll y){for (register int i=x;i<=n;i+=LB(i)) sum1[i]+=y,sum2[i]+=y*x;}
inline ll query(int x){ll ret=0;for (register int i=x;i;i^=LB(i)) ret+=1ll*(x+1)*sum1[i]-sum2[i];return ret;}
inline void add(int l,int r,int w){add(l,w);add(r+1,-w);}
inline ll query(int l,int r){return query(r)-query(l-1);}
int nxt[sz];
int main()
{
file();
int x,y;
read(n,Q,K);
rep(i,1,n) read(a[i]);
rep(i,1,Q) read(x,y),q[i]=(hh){x,y,i};
sort(q+1,q+Q+1,cmp);
int k=1;
drep(i,n,1)
{
nxt[i]=i+1;
int cur=a[i],lst=i;
for (int j=i+1,pre=i;j<=n;j=nxt[pre=j])
{
if ((cur&a[j])^cur)
{
if (cur%K==0) add(lst,j-1,1);
cur&=a[j];lst=j;
}
else nxt[pre]=nxt[j];
}
if (cur%K==0) add(lst,n,1);
while (q[k].pos==i&&k<=Q) ans[q[k].id]=query(1,q[k].r),++k;
}
rep(i,1,Q) printf("%lld\n",ans[i]);
}