[ARC086]F

来源:互联网 发布:js 运动轨迹 编辑:程序博客网 时间:2024/06/04 18:23

题面
可以证明,在最后一次÷2操作之前,不必要进行连续的两次1操作。因为连续的1操作可以通过先÷2来减少操作次数。
我们定义popcount(x)来表示x二进制表示中1的个数,那么假设做了k÷2操作(可以发现k不会超过60),那么可以把所有操作等价为:
1. p (p<2k),耗费popcount(p)次操作。
2. ÷2k,耗费k次操作。
3. d,耗费d次操作。
可以发现,经过前两次操作,一些数x变成了x÷2k,而另一些变成了x÷2k1。这取决于xmod2kp的大小关系。
设这些余数为Ci。那么对于每一个区间(Ci1,Ci],p取这个区间的任意值得出的序列都是等价的。
那我们会得到kn个序列,每一个序列都有一个最少已经消耗的操作次数k+minpopcount(Ci1,Ci],但是两个差分之后相同的序列是可以通过操作3相互转化的。
那么我们把差分序列相同的分成一类,那么一类中首项相同也就序列相同,每个序列的首项有一个取值范围[a1K+k+minpopcount(Ci1,Ci]a1],那么就相当于给定若干区间求并集长度的问题了,每一类DP一下即可。
总复杂度O(60n2log(n60))
代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define ll long longusing namespace std;const int mod=1000000007;int n,top,num;ll K,a[210],c[210],d[210];pair<ll,ll> qj[12010];struct node{    ll t[210],a1;    int k;}s[12010];bool operator <(const node &a,const node &b){    for(int i=1;i<n;i++)        if(a.t[i]<b.t[i]) return 1;        else if(a.t[i]>b.t[i]) return 0;    return 0; }bool check(node &a,node &b){    for(int i=1;i<n;i++)        if(a.t[i]!=b.t[i]) return 0;    return 1;   }int maxpop(ll x,ll y){    if(x==-1) return 0;    int re=0;    for(int i=60;i>=0;i--)        if(((x>>i)&1)==((y>>i)&1)) re+=((x>>i)&1);        else {re++;break;}    return re;  }ll dp(){    sort(qj+1,qj+num+1);    ll re=0,l=0,r=-1;    for(int i=1;i<=num;i++)    {        if(qj[i].first>r) {re+=(r-l+1);l=qj[i].first;}        r=qj[i].second;    }    re+=(r-l+1);    return re;  }int main(){    scanf("%d%lld",&n,&K);    for(int i=1;i<=n;i++)        scanf("%lld",&a[i]);    sort(a+1,a+n+1);        for(int i=0;i<=60;i++)    {        for(int j=1;j<=n;j++)            c[j]=(a[j]&((1ll<<i)-1));           sort(c+1,c+n+1);        c[0]=-1;        int sz=unique(c+1,c+n+1)-c-1;        for(int j=1;j<=sz;j++)            if(a[1]>=c[j])            {                int P=maxpop(c[j-1],c[j]);                for(int l=1;l<=n;l++)                    d[l]=((a[l]-c[j])>>i);                  s[++top].a1=d[1];s[top].k=i+P;                for(int l=1;l<n;l++)                    s[top].t[l]=d[l+1]-d[l];                    }    }    sort(s+1,s+top+1);    num=0;    ll ans=0;    for(int i=1;i<=top;i++)    {        if(i!=1&&!check(s[i],s[i-1])) ans=(ans+dp())%mod,num=0;         if(s[i].k<=K)qj[++num]=make_pair(max(s[i].a1-K+s[i].k,0ll),s[i].a1);    }    ans=(ans+dp())%mod;    printf("%lld",ans);    return 0;}