6442. 【GDOI2020模拟01.18】钩子

题目描述

Description

Input

Output

Sample Input
Sample Input1
3 1000000007

Sample Input2
4 1000000007

Sample Output
Sample Output1
0 1 0
500000004 0 500000004
500000004 0 500000004

Sample Output2
0 500000004 500000004 0
333333336 166666668 166666668 333333336
333333336 166666668 166666668 333333336
333333336 166666668 166666668 333333336

Data Constraint

题解

怒刚3h爆0

可以发现,操作的段可以分成log层,不同层之间段的先后顺序固定,同一层的可以互换

随便模拟一下可以得到每一层的奇数段数s1和偶数段数s2,考虑计算本层的概率

设\(f[i][j]\)表示已经放了i个奇数段,j个偶数段,那么当前可以放的位置数为\((s1-i)+2(s2-j)\),每个位置概率相等

设前面层的总人数为sum,那么在\(f[i][j]\)转移时就轮到第\(sum+i+j+1\)个人,可以算出每个人放在奇数段和偶数段的概率

显然放在奇数段的时候每个奇数段被放到的概率相等,所以可以求出第\(sum+1\sim sum+s1+s2\)个人的概率

往下做时,先假设偶数段只能放左边,做完之后把第\(sum+s1+s2+1\sim n\)个人在偶数段中的对称位置概率平均一下即可

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define add(a,b) a=((a)+(b))%mod
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
//#define file
using namespace std;

long long f[1001][1001];
long long g[1001][1001];
long long h[1002][2]; //0=odd 1=even
long long w[1001];
bool bz[1001];
int g1[21][1002];
int g2[21][1002];
int G[21][1002];
int n,i,j,k,l;
long long mod,Mod;

long long qpower(long long a,int b)
{
    long long ans=1;

    while (b)
    {
        if (b&1)
        ans=ans*a%mod;

        a=a*a%mod;
        b>>=1;
    }

    return ans;
}

void dg(int t,int sum)
{
    int i,j,k,l,mx=0,tot=0,s1=0,s2=0;

    fo(i,1,n) g1[t][i]=!bz[i]?g1[t][i-1]+1:0;
    fd(i,n,1) g2[t][i]=!bz[i]?g2[t][i+1]+1:0;
    fo(i,1,n) G[t][i]=min(g1[t][i],g2[t][i]);

    fo(i,1,n)
    mx=max(mx,G[t][i]);

    if (mx==1)
    {
        fo(i,1,n) tot+=!bz[i];

        fo(i,sum+1,n)
        {
            fo(j,1,n)
            if (!bz[j])
            f[i][j]=w[tot];
        }

        return;
    }

    fo(i,1,n)
    if (G[t][i]==mx)
    {
        if (G[t][i-1]!=mx && G[t][i+1]!=mx)
        ++s1;
        else
        if (G[t][i+1]==mx)
        ++s2;
    }

    memset(g,0,sizeof(g));
    g[0][0]=1;

    fo(i,0,s1)
    {
        fo(j,0,s2)
        if (i+j<=s1+s2)
        {
            if (i<s1)
            {
                add(g[i+1][j],g[i][j]*w[(s1-i)+(s2-j)*2]%mod*(s1-i)%mod);
                add(h[sum+i+j+1][0],g[i][j]*w[(s1-i)+(s2-j)*2]%mod*(s1-i)%mod);
            }
            if (j<s2)
            {
                add(g[i][j+1],g[i][j]*w[(s1-i)+(s2-j)*2]%mod*((s2-j)*2)%mod);
                add(h[sum+i+j+1][1],g[i][j]*w[(s1-i)+(s2-j)*2]%mod*((s2-j)*2)%mod);
            }
        }
    }

    fo(i,sum+1,sum+s1+s2)
    {
        fo(j,1,n-1)
        if (G[t][j]==mx)
        {
            if (G[t][j-1]!=mx && G[t][j+1]!=mx)
            f[i][j]=h[i][0]*w[s1]%mod;
            else
            if (G[t][j+1]==mx)
            {
                f[i][j]=h[i][1]*w[s2+s2]%mod;
                f[i][j+1]=h[i][1]*w[s2+s2]%mod;
            }
        }
    }

    fo(i,1,n)
    if (G[t][i]==mx && G[t][i-1]!=mx && G[t][i+1]!=mx || G[t][i]==mx && G[t][i+1]==mx)
    bz[i]=1;

    dg(t+1,sum+s1+s2);

    fo(j,1,n-1)
    if (G[t][j]==mx && G[t][j+1]==mx)
    {
        fo(i,sum+s1+s2,n)
        {
            fo(k,0,mx-1)
            {
                f[i][j-k]=(f[i][j-k]+f[i][j+k+1])*w[2]%mod;
                f[i][j+k+1]=f[i][j-k];
            }
        }
    }
}

int main()
{
    #ifdef file
    freopen("a.in","r",stdin);
    #endif

    scanf("%d%lld",&n,&mod);Mod=mod-2;

    w[1]=1;
    fo(i,2,1000)
    w[i]=mod-w[mod%i]*(mod/i)%mod;

    dg(1,0);

    fo(i,1,n)
    {
        fo(j,1,n)
        printf("%lld ",(f[i][j]+mod)%mod);
        printf("\n");
    }
}

原文地址:https://www.cnblogs.com/gmh77/p/12210937.html

时间: 2024-07-30 21:00:26

6442. 【GDOI2020模拟01.18】钩子的相关文章

6444. 【GDOI2020模拟01.18】树高

题目 正解 这题也不是给人写出来的-- 先不要考虑操作二. 有一种比较新奇的思路:将点的颜色挂在边上,然后搞出个边的连通块. 这些连通块的维护是很舒服的,直接上数据结构即可. 考虑边的连通块和点的连通块的关系. 假如有\(x\)和\(y\)和\(z\)三个点相连,\(x\)为\(y\)父亲,\(y\)为\(z\)父亲. \((x,y)\)和\((y,z)\)的颜色相同,意味着\(y\)和\(z\)的颜色相同. 推广一下,我们可以发现,对于一个边连通块而言,除了根节点(需要特判是不是整棵树的根节点

【GDOI2020模拟01.17】小 ω 玩游戏 (容斥+EGF)

小 ω 正在玩一个游戏. 小 ω 有一个 n 行 m 列的网格,初始每个方格中都有数字 0.她需要执行 q 次操作,每次操作可以选择其中一个方格 (x, y),然后先将第 x 行的数全部 +1,接着将第 y 列的数全部 +1. 小 ω 想知道有多少种执行操作的方式能使最后的网格中有不超过 k 个奇数. 两种方式不同当且仅当存在某一步中选择的方格坐标不同. \(1<=n,m<=2e5,q<=10^{18}\) 考虑行列分开,对行,算出\(f(x)\)表示恰好x行奇数的方案数,对列同理,算出

【GDOI2020模拟01.16】划愤(nim积+行列式)

https://gmoj.net/senior/#contest/show/2989/1 先考虑n=2时怎么做,打表找规律找了半天找不出来. 赛后才知道这是nim积. 定义\(x?y\)为\(sg(x,y)\). 有一坨性质: \(x,y<2^{2^k},x?y<2^{2^k}\) \(2^{2^k}?2^{2^k}={3 \over 2}2^{2^k}\) 可以把?看做乘法,\(⊕\)(异或)看做加法,所以还有分配律. 求\(x?y(x>y)\),设\(k\)为最大的\(k\)满足\(

【GDOI2020模拟01.16】树上的鼠 (博弈+长链剖分优化dp)

https://gmoj.net/senior/#contest/show/2989/2 思考什么时候先手会赢. 一开始双方都不会希望走到直径的端点上,因为那样对方就可以走直径而使自己输掉. 删掉直径的端点,考虑剩下的树的子问题. 如果又走到端点去了,对面就走到另外一个端点,那我就走到下一层的直径端点去了. 所以大家一直都不想走到直径端点. 一直删,如果最后只剩1一个点,说明先手必败,否则先手必胜. 如果是一条链,就是链的两边的长度不等先手就必胜. 如果是一棵树,考虑随便找一条直径,每次删去它的

6439. 【GDOI2020模拟01.17】小 ω 数排列

题目描述 Description Input Output Sample Input Sample Input1 4 10 3 6 2 9 Sample Input2 8 35 3 7 1 5 10 2 11 6 Sample Output Sample Output1 6 [样例 1 解释] 共有 6 个排列符合条件,它们是 (1, 3, 2, 4),(2, 4, 1, 3),(3, 1, 2, 4),(3, 1, 4, 2),(4, 2, 1, 3),(4, 2, 3, 1). Sample

6441. 【GDOI2020模拟01.17】小 ω 维护序列

Description Input Output 输出到标准输出流中. 若干行,对于每个操作 1 和操作 5,输出一个数表示答案. Sample Input Sample Input1 5 8 1 2 3 2 1 1 1 3 5 1 5 2 2 4 1 2 4 3 3 4 0 5 1 1 2 1 1 5 Sample Input2 10 15 5 4 3 5 4 1 5 4 3 1 2 8 580347 4 6 503576 1 2 5 5 8 11 1 2 6 4 7 565239 3 6 3

6445. 【GDOI2020模拟01.19】String

题目 正解 一听到正解是NTT,我心态崩了. 我特么知道是NTT都不知道该怎么做!哪里像个卷积了? 好吧,是我孤陋寡闻-- 设两个字符串分别为\(A\)和\(B\) 可以考虑试着计算出\(A\)每个子串和\(B\)的相似度(就是位置相同.字母相同的个数),直接统计就完事了. 看到字符集这么小,就可以对于每个字母分开考虑. 假如\(A_i=B_j\),那么以\(A_{i-j+1}\)开头的子串就有\(1\)的贡献. 这样一来,看起来就很像是个卷积了. 搞完之后将贡献加起来,统计即可. 总结 还是没

6447. 【GDOI2020模拟01.19】sort

题目 正解 这题一看也是不能写的题目-- 用个平衡树来维护. 平衡树维护的是一个\(Trie\)的序列.每个\(Trie\)表示这段区间中所有数都会排序一遍. 进行各种操作时,首先会将至多两个节点的\(Trie\)分裂.分裂\(Trie\)会新增\(O(\lg n)\)个节点. 然后将整段区间旋到一棵子树内,然后打标记.平衡树和\(Trie\)上都要打标记. 排序是时候将若干个\(Trie\)合并成一个. 由于这些\(Trie\)是带标记的,所以要将标记下传.\(Trie\)树上标记下传时,如果

6438. 【GDOI2020模拟01.16】树上的鼠

题目 由于时间过于久远,而且题面本身也很清晰,所以就懒得另外叙述题目大意了(还有思考历程). 正解 先考虑一条链的情况(长度为奇数,这里的长度是指点的数量): 如果根在中点,先手无论移到哪里,后手都可以移到它的对称点去. 此时先手必败: 如果根不在中点,先手只要一开始移到中点,先手就赢了. 若长度为偶数,就将中间的两个点都看成中点. 先手第一步先移到离根比较远的那个中点上,以后就用一样的策略,每次到达对方的对称点.所以偶数时先手必胜. 然后这就可以推广到一棵树的情况. 可以发现先手必败的情况当且