码迷,mamicode.com
首页 > 其他好文 > 详细

dtoi4699 序列

时间:2020-02-05 00:06:37      阅读:120      评论:0      收藏:0      [点我收藏+]

标签:while   ||   位置   快速幂   else   roo   space   它的   lin   

题意:

     已知大小为n的一个排列,对于任意一个子序列s,它对ans[k]的贡献为(对于任意的i<|s|,满足s[i]>k>s[i+1]或者s[i]<k<s[i+1]的i的数量)。输出ans[k],k∈[1,n]

题解:

     由于个人比较菜,所以我的方法很奇怪。

     从小到大枚举i,考虑每一次“点亮”它所在的位置,那么当前的答案就是所有“亮”的位置和“不亮”的位置的贡献。

     对于一组合法的(i,j),它对答案的贡献就是2^(n-(j-i+1))。

     那么我有一个位置亮了起来,它对答案就会新增暗的地方对它的贡献,所以说我们就用总的贡献减去亮的地方对它的贡献,那么亮的地方对它的贡献可以用线段树维护。大概就是维护一个等比数列,因为等比数列+等比数列还是等比数列,当然比要相等,本题中比只会有2或1/2,所以可以使用线段树维护。

     然而本题空间5M(不知道出题人想干啥),于是我就把原本正常的代码各种乱改,以时间换空间甚至是小范围分块大范围快速幂求a^b。然后卡着1s过去了。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int mod=1e9+7;
int n,a,t[100002],d,ans,cf[30002];
typedef struct{
    int sx1,sc1,sx2,sc2;
}P;
P p[300002];
inline long long ccj(long long x,long long y){
    if (x==2 && y<=100000)
    {
        int ans=1;
        if (y<=30000)return cf[y];
        while(y>=30000)
        {
            ans=(long long)ans*cf[30000]%mod;y-=30000;
        }
        ans=(long long)ans*cf[y]%mod;
        return ans;
    }
    int ans=1;
    while(y)
    {
        if (y&1)ans=ans*x%mod;
        x=x*x%mod;y>>=1;
    }
    return ans;
}
inline void gengxin1(int root,int begin,int end,int begin2,int end2,int sx,bool u){
    if (begin>end2 || end<begin2)return;
    if (begin>=begin2 && end<=end2)
    {
        if (u)
        {
            p[root].sx1=(p[root].sx1+(long long)sx*ccj(2,begin-begin2)%mod)%mod;
        }
        else
        {
            p[root].sc1=(p[root].sc1+(long long)sx*ccj(ccj(2,begin-begin2)%mod,mod-2))%mod;
        }
        return;
    }
    int mid=(begin+end)/2;
    gengxin1(root*2,begin,mid,begin2,end2,sx,u);gengxin1(root*2+1,mid+1,end,begin2,end2,sx,u);
}
inline void gengxin2(int root,int begin,int end,int begin2,int end2,int sx,bool u){
    if (begin>end2 || end<begin2)return;
    if (begin>=begin2 && end<=end2)
    {
        if (u)
        {
            p[root].sx2=(p[root].sx2+(long long)sx*ccj(2,begin-begin2)%mod)%mod;
        }
        else
        {
            p[root].sc2=(p[root].sc2+(long long)sx*ccj(ccj(2,begin-begin2)%mod,mod-2)%mod)%mod;
        }
        return;
    }
    int mid=(begin+end)/2;
    gengxin2(root*2,begin,mid,begin2,end2,sx,u);gengxin2(root*2+1,mid+1,end,begin2,end2,sx,u);
}
inline void chaxun1(int root,int begin,int end,int wz){
    ans=(ans-ccj(2,wz-begin)*p[root].sx1%mod)%mod;
    ans=(ans-ccj(ccj(2,wz-begin),mod-2)*p[root].sc1%mod)%mod;
    ans=(ans+mod)%mod;
    if (begin==end)return;
    int mid=(begin+end)/2;
    if (wz<=mid)chaxun1(root*2,begin,mid,wz);
    else chaxun1(root*2+1,mid+1,end,wz);
}
inline void chaxun2(int root,int begin,int end,int wz){
    ans=(ans-ccj(2,wz-begin)*p[root].sx2%mod)%mod;
    ans=(ans-ccj(ccj(2,wz-begin),mod-2)*p[root].sc2%mod)%mod;
    ans=(ans+mod)%mod;
    if (begin==end)return;
    int mid=(begin+end)/2;
    if (wz<=mid)chaxun2(root*2,begin,mid,wz);
    else chaxun2(root*2+1,mid+1,end,wz);
}
int main()
{
    scanf("%d",&n);cf[0]=1;
    for (int i=1;i<=30000;i++)cf[i]=cf[i-1]*2%mod;
    for (int i=1;i<=n;i++){scanf("%d",&a);t[a]=i;}
    for (int i=1;i<=n;i++)
    {
        chaxun2(1,1,n,t[i]);
        printf("%lld\n",ans);d=0;
        int t1=ccj(2,n-2),t2=ccj(2,n-t[i]),t3=ccj(2,n-t[i]);
        if (t[i]<n)
        {
            gengxin1(1,1,n,t[i]+1,n,t1,0);
            gengxin2(1,1,n,t[i]+1,n,t1,0);
            d=((t1*2%mod-1)-ccj(2,t[i]-1)+1)%mod;
            d=(d%mod+mod)%mod;
        }
        if (t[i]>1)
        {
            gengxin1(1,1,n,1,t[i]-1,t3,1);
            gengxin2(1,1,n,1,t[i]-1,t3,1);
            d=(d+(t1*2%mod-1)-t2+1)%mod;
            d=(d%mod+mod)%mod;
        }
        ans=(ans+d)%mod;chaxun1(1,1,n,t[i]);
    }
    return 0;
}

 

dtoi4699 序列

标签:while   ||   位置   快速幂   else   roo   space   它的   lin   

原文地址:https://www.cnblogs.com/1124828077ccj/p/12261930.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!