AtCoder Beginner Contest 217G - Groups

从小清新题目开始的康复之旅

G - Groups

Problem Statement

You are given positive integers $N$ and $M$. For each $k=1,…,N$, solve the following problem.

  • Problem: We will divide $N$ people with ID numbers $1$ through $N$ into $k$ non-empty groups. Here, people whose ID numbers are equal modulo $M$ cannot belong to the same group.
    How many such ways are there to divide people into groups?
    Since the answer may be enormous, find it modulo $998244353$.

Here, two ways to divide people into groups are considered different when there is a pair $(x,y)$ such that Person $x$ and Person $y$ belong to the same group in one way but not in the other.

Constraints

  • $2≤N≤5000$
  • $2≤M≤N$
  • All values in input are integers.

题目分析

一个组合数学题

一开始想简单了,以为是一个最简单的容斥,考虑最多分成n组的情况减去最多分成n-1组的情况,以为这个就是恰好n组的情况

递推地看第n项的答案f(n),首先钦定某一个剩余类$a_1$的位置,其余的剩余类$a_j$随意插空有$\Pi A(n, a_j)$种方案,然后减去恰好包含$n-1$项$f(n-1)*A(n-a_1,(n-1)-a_1)$,$n-2$项$f(n-2)*A(n-a_1,(n-2)-a_1)$...的方案。最后因为方案是无序的,再除以$(n-a_1)!$

CE了一发emmm根本没想起来atcoder不能用万能头

// #include<bits/stdc++.h>
#include<cstdio>
const int MO = 998244353;
const int maxn = 5035;

int n,m,a[maxn],f[maxn],fac[maxn],inv[maxn];

int A(int n, int m)
{
    return 1ll*fac[n]*inv[n-m]%MO;
}
int C(int n, int m)
{
    return 1ll*fac[n]*inv[n-m]%MO*inv[m]%MO;
}
void Inc(int &x, int y)
{
    x = (x+y+MO)%MO;
}
void Dec(int &x, int y)
{
    x = (x-y+MO)%MO;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n%m; i++) a[i] = n/m+1;
    for (int i=n%m+1; i<=m; i++) a[i] = n/m;
    inv[0] = inv[1] = fac[1] = 1;
    for (int i=2; i<=n; i++)
        inv[i] = 1ll*(MO-MO/i)*inv[MO%i]%MO;
    for (int i=2; i<=n; i++)
        inv[i] = 1ll*inv[i-1]*inv[i]%MO, fac[i] = 1ll*fac[i-1]*i%MO;
    for (int i=1; i<a[1]; i++) f[i] = 0;
    for (int i=a[1]; i<=n; i++)
    {
        int cnt = 1;
        for (int j=2; j<=m; j++)
            cnt = 1ll*cnt*A(i, a[j])%MO;
        Inc(f[i], cnt);
        for (int j=a[1]; j<i; j++)
            Dec(f[i], 1ll*f[j]*A(i-a[1], j-a[1])%MO);
        f[i] = 1ll*f[i]*inv[i-a[1]]%MO;
    }
    for (int i=1; i<=n; i++) printf("%d\n",f[i]);
    return 0;
}

 

 

 

END

posted @ 2021-09-14 22:31  AntiQuality  阅读(78)  评论(1编辑  收藏  举报