轮换+区间+收集果子

来源:互联网 发布:mac工商银行网银控件 编辑:程序博客网 时间:2024/05/16 04:44

这里写图片描述
这里写图片描述
理解了题意就很容易模拟了。
从后向前,然后括号里面的不是位置,而是数。

#include <cstdio>#include <iostream>#include <vector>using namespace std;int w[99999];int z[1001][1001];int w2[99999];int main(){    freopen("rotate.in","r",stdin);    freopen("rotate.out","w",stdout);    int n,q,k;    scanf("%d%d%d",&n,&q,&k);    for(int i=1;i<=n;i++)     w[i]=i;    for(int i=1;i<=q;i++)    {        int m;        scanf("%d",&m);        z[i][0]=m;        for(int j=1,x;j<=m;j++)         scanf("%d",&z[i][j]);    }    for(int i=q;i>=1;i--)    {        int tmp=w[z[i][z[i][0]]];        for(int j=z[i][0];j>1;j--)         w[z[i][j]]=w[z[i][j-1]];        w[z[i][1]]=tmp;    }    for(int i=1;i<=n;i++)    {        for(int j=1;j<=n;j++)         if(w[j]==i)         {            printf("%d ",j);            break;         }    }    /*for(int j=1;j<=n;j++)     printf("%d ",w[j]);*/} 

这里写图片描述
这里写图片描述

ST表处理

先处理出i->i+2^j的or和and

方法1:二分答案
用二分优化i->j j走的过程,直接找出一段连续区间相同的,然后直接跳。

方法2:倍增找答案

对于一个i
直接倍增找i最近能满足条件的j和最远的j

方法1:二分(极端数据肯定T)

#include <cstdio>#include <iostream>#include <vector>#include <cmath>using namespace std;const int mod=1e9+7;int ana[110000][21],ord[110000][21];int q[110000]; int get_and(int l,int r){    int len=(r-l)+1;    int t=log2(len);    return ana[l][t]&ana[r-(1<<t)+1][t]; }int get_or(int l,int r){    int len=(r-l)+1;    int t=log2(len);    return ord[l][t]|ord[r-(1<<t)+1][t]; }int main(){    freopen("range.in","r",stdin);    //freopen("range.out","w",stdout);    int n,a,b,c,d;    scanf("%d%d%d%d%d",&n,&a,&b,&c,&d);    for(int i=1;i<=n;i++)     scanf("%d",&q[i]),ana[i][0]=q[i],ord[i][0]=q[i];    for(int j=1;j<=20;j++)     for(int i=1;i<=n;i++)      if(i+(1<<j)-1<=n)      {        ana[i][j]=ana[i][j-1]&ana[i+(1<<j-1)][j-1];        ord[i][j]=ord[i][j-1]|ord[i+(1<<j-1)][j-1];      }    long long cnt=0;    for(int i=1;i<=n;i++)     {        int andx=q[i],orx=q[i];        for(int j=i;j<=n;j++)        {            int l=j,r=n+1;//起点终点             int flag=1;            andx=get_and(i,j);            orx=get_or(i,j);            if(a<=andx&&b>=andx&&c<=orx&&d>=orx) flag=0;            //if(flag) continue;            int ans=0;            while(l<=r)            {                int mid=(l+r)/2;                if(andx&&get_and(i,mid)==andx&&orx&&get_or(i,mid)==orx) l=mid+1,ans=mid;                else r=mid-1;            }            if(ans)            {                if(a<=andx&&b>=andx&&c<=orx&&d>=orx) cnt+=(ans-j+1)%mod;                j=ans;            }            else break;        }     }     printf("%lld\n",cnt%mod);}

方法2:倍增

#include <cstdio>#include <iostream>#include <vector>#include <cmath>using namespace std;const int mod=1e9+7;int ana[110000][21],ord[110000][21];int q[110000]; int get_and(int l,int r){    int len=(r-l)+1;    int t=log2(len);    return ana[l][t]&ana[r-(1<<t)+1][t]; }int get_or(int l,int r){    int len=(r-l)+1;    int t=log2(len);    return ord[l][t]|ord[r-(1<<t)+1][t]; }int main(){    freopen("range.in","r",stdin);    //freopen("range.out","w",stdout);    int n,a,b,c,d;    scanf("%d%d%d%d%d",&n,&a,&b,&c,&d);    for(int i=1;i<=n;i++)     scanf("%d",&q[i]),ana[i][0]=q[i],ord[i][0]=q[i];    for(int j=1;j<=20;j++)     for(int i=1;i<=n;i++)      if(i+(1<<j)-1<=n)      {        ana[i][j]=ana[i][j-1]&ana[i+(1<<j-1)][j-1];        ord[i][j]=ord[i][j-1]|ord[i+(1<<j-1)][j-1];      }    long long cnt=0;    for(int i=1;i<=n;i++)     {        int tmp1=i,tmp2,s1=(1<<19)-1,s2=0;        if(ana[i][0]<a||ord[i][0]>d) continue;        for(int k=18;k>=0;k--)         if(tmp1+(1<<k)-1<=n)          if(((ana[tmp1][k]&s1)>b)||((ord[tmp1][k]|s2)<c)) s1&=ana[tmp1][k],s2|=ord[tmp1][k],tmp1+=(1<<k);        tmp2=tmp1;        for(int k=18;k>=0;k--)         if(tmp1+(1<<k)-1<=n)          if(((ana[tmp1][k]&s1)>=a)&&((ord[tmp1][k]|s2)<=d)) s1&=ana[tmp1][k],s2|=ord[tmp1][k],tmp1+=(1<<k);        tmp1--;        if(tmp1-tmp2>=1)         cnt+=(tmp1-tmp2+1);     }     printf("%lld\n",cnt%mod);}

收集果子,还没做。。。

原创粉丝点击