对于每个位置都可以暴力的找到最右边的一个点使之后的点再异或异或和下降。
可以维护一颗主席树,外层表示的是起点,内层表示的是以该点为起点的所以终点的合法区间。
每次利用前缀和作差即可。因为是区间操作所以我们标记永久化一下。
#include
#include
#include
#include
#include
#define N 100003
using namespace std;
struct data{
int ls,rs,x,sum;
}tr[N*60];
int a[N],n,m,sz,root[N];
void update(int i,int lx,int rx)
{
int l=tr[i].ls; int r=tr[i].rs;
tr[i].sum=tr[i].x*(rx-lx+1);
if (l) tr[i].sum+=tr[l].sum;
if (r) tr[i].sum+=tr[r].sum;
}
void insert(int &i,int j,int l,int r,int ll,int rr)
{
i=++sz;
tr[i]=tr[j];
if (ll<=l&&r<=rr) {
tr[i].x+=1;
update(i,l,r);
return;
}
if (l==r) return;
int mid=(l+r)/2;
if (ll<=mid) insert(tr[i].ls,tr[j].ls,l,mid,ll,rr);
if (rr>mid) insert(tr[i].rs,tr[j].rs,mid+1,r,ll,rr);
update(i,l,r);
}
int qjchange(int i,int j,int l,int r,int ll,int rr,int v)
{
if (ll<=l&&r<=rr) return tr[i].sum-tr[j].sum+(r-l+1)*v;
int mid=(l+r)/2; int ans=0;
if (ll<=mid) ans+=qjchange(tr[i].ls,tr[j].ls,l,mid,ll,rr,v+tr[i].x-tr[j].x);
if (rr>mid) ans+=qjchange(tr[i].rs,tr[j].rs,mid+1,r,ll,rr,v+tr[i].x-tr[j].x);
return ans;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) {
int x=0; int pos=i;
for (int j=i;j<=n;j++)
if ((x^a[j])>=x) x^=a[j],pos=j;
else break;
// cout<" "<<pos<1],1,n,i,pos);
}
scanf("%d",&m);
int ans=0;
for (int i=1;i<=m;i++) {
int l,r; scanf("%d%d",&l,&r);
l=(l+ans)%n+1; r=(r+ans)%n+1;
// cout<" "<if (l>r) swap(l,r);
ans=qjchange(root[r],root[l-1],1,n,l,r,0);
printf("%d\n",ans);
}
}
从高的开始消,消到左右两边较高的位置,然后把他们合并成一大列一起向下消。
关键就是怎么划分,对于每一大列维护del[i]表示的是如果当前阶段继续向下消,上面还有多少空可以补。
#include
#include
#include
#include
#include
#include
#define N 200003
#define LL long long
using namespace std;
setlong long,int> > p;
LL k,f[N],h[N],del[N]; int n,l[N],r[N],fa[N];
int find(int x)
{
if (fa[x]==x) return x;
fa[x]=find(fa[x]);
return fa[x];
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%lld",&n,&k);
for (int i=1;i<=n;i++) scanf("%lld",&h[i]);
for (int i=1;i<=n;i++) {
p.insert(make_pair(h[i],i));
l[i]=r[i]=fa[i]=i;
}
LL ans=0;
while (p.size()) {
int x=(*--p.end()).second;
p.erase(--p.end());
LL L=l[x]-1==0?0:h[find(l[x]-1)];
LL R=r[x]+1==n+1?0:h[find(r[x]+1)];
LL hi=max(L,R);
LL sum=(LL)(r[x]-l[x]+1)*(h[x]-hi);
if (del[x]>=sum) del[x]-=sum;
else sum-=del[x],ans+=(sum-1)/k+1,del[x]=(k-sum%k)%k;
h[x]=hi;
if (hi!=0) {
if (L==hi) {
int t=find(l[x]-1);
del[x]+=del[t];
p.erase(make_pair(L,t));
fa[t]=x; l[x]=l[t];
}
if (R==hi) {
int t=find(r[x]+1);
del[x]+=del[t];
p.erase(make_pair(R,t));
fa[t]=x; r[x]=r[t];
}
p.insert(make_pair(h[x],x));
}
}
printf("%lld\n",ans);
}
首先需要知道斐波那契数列的一个性质
#include
#include
#include
#include
#include
#define N 1000003
#define p 1000000007
#define LL long long
using namespace std;
int mu[N],a[N],cnt[N],h[N],g[N],n,pd[N],prime[N],f[N];
LL quickpow(LL num,int x)
{
LL ans=1,base=num%p;
x=(x%(p-1)+p-1)%(p-1);
while (x) {
if (x&1) ans=ans*base%p;
x>>=1;
base=base*base%p;
}
return ans;
}
void init(int n)
{
mu[1]=1;
for (int i=2;i<=n;i++) {
if (!pd[i]) {
prime[++prime[0]]=i;
mu[i]=-1;
}
for (int j=1;j<=prime[0];j++) {
if (prime[j]*i>n) break;
pd[i*prime[j]]=1;
if (i%prime[j]==0) break;
mu[i*prime[j]]=-mu[i];
}
}
f[0]=0; f[1]=1;
for (int i=2;i<=n;i++) f[i]=(f[i-1]+f[i-2])%p;
for (int i=1;i<=n;i++) {
if (!h[i]) continue;
for (int j=i;j<=n;j+=i) g[i]+=h[j]*mu[j/i];
}
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&n);
int mx=0;
for (int i=1;i<=n;i++) scanf("%d",&a[i]),mx=max(a[i],mx);
for (int i=1;i<=n;i++) {
for (int x=1;x*x<=a[i];x++)
if (a[i]%x==0) h[x]=1,h[a[i]/x]=1;
}
init(mx);
LL ans=1;
for (int i=1;i<=mx;i++)
ans=ans*quickpow(f[i],g[i])%p;
printf("%lld\n",ans);
}