• GMOJ 6809 不难题 题解


    考虑我们已经有区间([L, R]),设(f_i)为在进行若干次操作后第i个恶魔连续出现在末尾且前面没有连续出现的恶魔的方案数。

    先不考虑前面有没有连续出现,再枚举前面可以连续出现的恶魔去除掉。

    [f_i = frac{(sum_{jin[L, R]} p_{i, j}-1)!}{prod_{jin[L, R]}(p_{i,j}-1)!}cdot(R-L+1)! - sum_{jin S}f_jcdot frac{(sum_{xin[L, R]}p_{i,x}-p_{j,x}-1)!}{prod_{xin[L, R]}(p_{i,x}-p_{j,x}-1)!}cdot(R-L+1)! ]

    其中(S)代表可以连续出现在i以前的恶魔编号集合,(p_{i,j})表示i恶魔在j井中的位置。

    我们在每口井后面都增加一个n+1的恶魔,这样答案就是(frac {f_{n+1}} {(R-L+1)!})

    朴素的算法是(O(n^2k^3))的,但是我们发现固定左端点,枚举右端点时,分式的分子与分母分开来容易维护。注意到随机数据,那么(S)每次期望缩小(frac 1 2),时间复杂度就变成了(O(nk(n+k)))

    然而我还是要吸口氧才能过

    #pragma GCC optimize("-O2")
    #include <cstdio>
    
    using namespace std;
    
    typedef long long ll;
    const int maxk=300, maxn=301, mods=1000000007;
    
    ll fact[maxk*maxn+1], invf[maxk*maxn+1];
    
    ll qpower(ll a, int n) {
        ll s=1;
        for (; n; n/=2) {
            if (n&1) s=s*a%mods;
            a=a*a%mods;
        }
        return s;
    }
    
    void initFact(int n) {
        fact[0] = 1;
        for (int i=1; i<=n; i++) fact[i] = fact[i-1]*i%mods;
        invf[n] = qpower(fact[n], mods-2);
        for (int i=n; i>0; i--) invf[i-1] = invf[i]*i%mods;
    }
    
    int main() {
        freopen("nothard.in", "r", stdin);
        freopen("nothard.out", "w", stdout);
    
        static int a[maxk+1][maxn+1], p[maxn+1][maxk+1];
        int k, n;
        scanf("%d %d", &k, &n);
        initFact(n*k);
        for (int i=1; i<=k; i++) {
            for (int j=1; j<=n; j++) {
                scanf("%d", a[i]+j);
                p[i][a[i][j]] = j;
            }
            a[i][n+1] = p[i][n+1] = n+1;
        }
        n++;
    
        static int cor[2][maxn+1][maxn+1];
        static ll f[maxn+1], u[maxn+1][maxn+1], v[maxn+1][maxn+1];
        ll ans=0, now=0;
        for (int i=1; i<=k; i++) {
            int pos=0;
            for (int j=1; j<=n; j++) {
                int o=a[i][j];
                cor[pos][o][0] = j-1;
                u[o][o]=j-1;
                v[o][o]=invf[j-1];
                for (int t=1; t<j; t++) {
                    cor[pos][o][t] = a[i][t];
                    u[o][a[i][t]] = j-t-1;
                    v[o][a[i][t]] = invf[j-t-1];
                }
            }
    
            for (int j=i+1; j<=k; j++) {
                static int book[maxn+1];
                book[0]++;
                pos=!pos;
                for (int x=1; x<=n; x++) {
                    int o=a[j][x];
                    u[o][o] += x-1;
                    v[o][o] = v[o][o]*invf[x-1]%mods;
                    f[o] = fact[u[o][o]]*v[o][o]%mods*fact[j-i+1]%mods;
    
                    cor[pos][o][0] = 0;
                    for (int y=1; y<=cor[!pos][o][0]; y++) {
                        int z=cor[!pos][o][y];
                        if (book[z]==book[0]) {
                            cor[pos][o][++cor[pos][o][0]] = z;
    
                            int t=x-p[j][z]-1;
                            u[o][z] += t;
                            v[o][z] = v[o][z]*invf[t]%mods;
                            f[o] = (f[o]+mods-f[z]*fact[u[o][z]]%mods*v[o][z]%mods*fact[j-i+1]%mods)%mods;
                        }
                    }
                    book[o] = book[0];
                }
    
                ans = (ans+f[n]*invf[j-i+1]%mods)%mods;
            }
        }
    
        printf("%lld
    ", ans);
    
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    
    
  • 相关阅读:
    java 语言里 遍历 collection 的方式
    struts2启动报错com/opensymphony/xwork2/spring/SpringObjectFactory.java:220:-1
    mysql 查看表的类型
    memcached—向memcached中保存Java实体需注意的问题
    一个关于 UIPickerView 的 bug
    Wireshark数据抓包教程之安装Wireshark
    Mysql第四天 数据库设计
    产品经理怎样才干把一件事做出色
    Tokyo Tyrant(TTServer)系列(三)-Memcache协议
    Unity3D
  • 原文地址:https://www.cnblogs.com/BunnyLutts/p/13913049.html
Copyright © 2020-2023  润新知