排列

排列

https://ac.nowcoder.com/acm/problem/13332

分析

我们对于一个节点 考虑,如果有一个点 两维都大于 ,那么这个节点肯定不可能作为结尾。因为考虑一下,如果排列先出现 ,那么这个两维都是单调不降的,所以不可能转移到 ,反之,如果先出现 ,它一定保持不住结尾,最后整个图构成了一个有向无环图,每一个节点可以等概率转移到后置节点。那么一个节点对于它后面节点贡献就为,令考虑前 个,当前节点为结尾的概率 。那么它的贡献的计算 。因为它的贡献要被后面的节点等概率转移,所以 。那么这个就是个二维偏序的问题,考虑树状数组优化。先求出 。然后由小到大枚举 就好了,最后还要乘以所有方案数。时间复杂度为

代码

#include<bits/stdc++.h> 
using namespace std;
#define LL long long
LL read() {
    LL x = 0,f = 0;char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-')f=1;ch=getchar();}
    while(isdigit(ch)) {x = x * 10 + ch - '0';ch = getchar();}
    return f ? -x : x;
}
const LL mod = 1e9 + 7,N = 1e6 + 1000;
LL X[N],Y[N],inv[N],f[N],t[N],num[N],n;
void add(LL x,LL y) {
    for(LL i = x;i <= n;i+=i&-i) t[i] = (t[i] + y) % mod;
}
LL ask(LL x) {
    LL tot = 0;
    for(LL i = x;i;i -= i&-i) tot = (tot + t[i] + mod) % mod;
    return tot;
}
int main() {
    n = read();
    for(int i = 1;i <= n;i++) {
        int x = read();X[i] = x;Y[x] = read(); 
    }
    inv[0] = inv[1] = 1;
    for(int i = 2;i <= n;i++) inv[i] = (mod - (mod/i) * inv[mod % i] % mod + mod) % mod;
    for(int i = n;i >= 1;i--) {
        num[i] = n - i - ask(Y[i]);add(Y[i],1);
    }
    LL fac = 1;
    for(int i = 1;i < n;i++) fac = fac * i % mod;
    memset(t ,0 ,sizeof(t));
    add(1,1);
    for(int i = 1;i <= n;i++) {
        f[i] = inv[num[i]] * (ask(Y[i])) % mod;
        add(Y[i],f[i]);
    }
    for(int i = 1;i <= n;i++) {
        int id = X[i];
        if(num[id] == 0) printf("%lld\n",f[id] * fac % mod);
        else printf("0\n");
    }
}
全部评论
好厉害啊...不愧是大佬..
1 回复 分享
发布于 2020-09-21 20:32
我看看
1 回复 分享
发布于 2020-09-21 20:32
1 回复 分享
发布于 2020-09-21 20:33
大佬你好,抱歉打扰您。如果可以的话能请稍微解释下这题概率转移是什么意思吗,我实在想象不出前面的点对后面的点的贡献是怎么运作的。
点赞 回复 分享
发布于 2023-04-19 23:39 浙江
好像有眉目了,谢谢您
点赞 回复 分享
发布于 2023-04-20 00:10 浙江

相关推荐

11-28 17:58
门头沟学院 Java
美团 JAVA开发 n×15.5
牛客786276759号:百度现在晋升很难的 而且云这块的业务没美团好 你看百度股价都跌成啥样了
点赞 评论 收藏
分享
11-18 16:08
福州大学 Java
影流之主:干10年不被裁,我就能拿别人一年的钱了,日子有盼头了
点赞 评论 收藏
分享
评论
5
3
分享
牛客网
牛客企业服务