牛客小白月赛23f美丽的序列I,数学+分类

美丽的序列I

https://ac.nowcoder.com/acm/contest/4784/F

一个不降序列本身度是1,要分成若干不降,那么每降的地方就分割一次,所以就转变成求序列有多少前>后——分割次数
一个确定数列的美丽度=1+分割次数
1是每个数列都要加的,分割次数不确定(可能为0)
所有的1的和=可以排成的数列方案数
分割次数和=(遍历每两个相邻数)ai>ai+1的组合数*贡献(即不考虑这两个位置,其他位置的组合数)
前的情况大概怎么几种

情况-1,-2是没有前<后的
特别注意情况1和2是不同的
2中6有5种方法,5只有4种方法
先算斜阴影,
再算竖阴影,因为是点的方法连续递增1,所以(最大+最少)*数量  求和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7,N=1e5+10;

ll n,inv2,l[N],r[N],pro[N],repro[N],pl,pr,el,er,ans,big,small,num;
ll qmi(ll a,ll b,ll mod){
    ll ans=1;
    while(b){
    	if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}

int main(){
    cin>>n;
    inv2=qmi(2,mod-2,mod);
    for(int i=1;i<=n;i++){
        cin>>l[i]>>r[i];
    }
    pro[0]=1; for(int i=1;i<=n;i++) pro[i]=pro[i-1]*(r[i]-l[i]+1)%mod;
    repro[n+1]=1; for(int i=n;i>=1;i--) repro[i]=repro[i+1]*(r[i]-l[i]+1)%mod;
    ans=pro[n];
    for(int i=2;i<=n;i++){
        pl=l[i-1], pr=r[i-1];
        el=l[i], er=r[i];
        if(pr<=el) continue;
        if(pl>er){//情况1
            ans=(ans+(er-el+1)*(pr-pl+1)%mod*pro[i-2]%mod*repro[i+1]%mod)%mod;
            continue;
        }
        if(pr>er){//斜阴影
            ans=(ans+(pr-er)*(er-el+1)%mod*pro[i-2]%mod*repro[i+1]%mod)%mod;
            pr=er;
        }
        //竖阴影
        big=pr-el; small=max(pl-el,0LL);
        num=big-small+1;
        ans=(ans+(big+small)*num%mod*inv2%mod*pro[i-2]%mod*repro[i+1]%mod)%mod;
    }
    cout<<ans;
    return 0;
}

创作不易
全部评论

相关推荐

牛客717484937号:双飞硕没实习挺要命的
点赞 评论 收藏
分享
Pandaileee:校友加油我现在也只有一个保底太难了
点赞 评论 收藏
分享
3 收藏 评论
分享
牛客网
牛客企业服务