UOJ #390. 【UNR #3】百鸽笼

UOJ #390. 【UNR #3】百鸽笼

题目链接

看这道题之前先看一道相似的题目 【PKUWC2018】猎人杀

考虑类似的容斥:

我们不妨设处理\(1\)的概率。

我们另集合\(T\)中的所有鸽笼都在\(1\)变空之前不为空的,其它的鸽笼随便。要做到这一点,我们只需要令每个\(T\)集合中的鸽笼容量\(--\)就行了。然后我们用背包背出所有序列的方案数(不包括\(1\)),然后在将\(1\)插入序列中。插入时,将\(w_i-1\)个随便插入,然后再将一个放在序列末尾。

具体实现时,我们可以枚举"\(1\)",然后对其它的鸽笼进行背包。但是复杂度会达到\(O(n^6)\)。于是我们先对所有鸽笼进行背包,计算"\(1\)"的时候直接将它的贡献消除,也就是做"反背包"。复杂度就是\(O(n^5)\)。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 35
#define mod 998244353

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

int n,w[N];
ll ksm(ll t,ll x) {
    ll ans=1;
    for(;x;x>>=1,t=t*t%mod)
        if(x&1) ans=ans*t%mod;
    return ans;
}

ll fac[1005],inv[1005];
ll C(int n,int m) {
    if(n<m) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}

ll f[N][N*N];
ll g[N][N*N];
int sum;

void solve(int now) {
    memcpy(f,g,sizeof(f));
    for(int i=1;i<=n;i++) {
        for(int j=0;j<=sum;j++) {
            for(int q=0;q<w[now]&&q<=j;q++) {
                f[i][j]=(f[i][j]-f[i-1][j-q]*C(j,q)%mod+mod)%mod;
            }
        }
    }
    ll ans=0,flag=1;
    for(int i=0;i<n;i++,flag*=-1) {
        ll invi=ksm(i+1,mod-2),t=ksm(invi,w[now]);
        for(int j=0;j<=sum;j++,t=t*invi%mod) {
            if(!f[i][j]) continue ;
            (ans+=flag*C(j+w[now]-1,w[now]-1)*f[i][j]%mod*t%mod)%=mod;
        }
    }
    cout<<(ans+mod)%mod<<" ";
}

int main() {
    fac[0]=1;
    for(int i=1;i<=900;i++) fac[i]=fac[i-1]*i%mod;
    inv[900]=ksm(fac[900],mod-2);
    for(int i=899;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
    n=Get();
    for(int i=1;i<=n;i++) w[i]=Get();
    g[0][0]=1;
    for(int i=1;i<=n;i++) {
        sum+=w[i]-1;
        for(int j=i;j>=1;j--) {
            for(int k=sum;k>=0;k--) {
                for(int q=0;q<w[i]&&q<=k;q++) {
                    (g[j][k]+=g[j-1][k-q]*C(k,q))%=mod;
                }
            }
        }
    }
    for(int i=1;i<=n;i++) solve(i);
    return 0;
}

原文地址:https://www.cnblogs.com/hchhch233/p/10159901.html

时间: 2024-07-30 04:27:55

UOJ #390. 【UNR #3】百鸽笼的相关文章

UNR #3 百鸽笼

题目大意:在UOJ管理员群里一共有\(N\)个管理员,为了容纳这些管理员,vfk准备了\(N+1\)个鸽笼. 为了节省空间,vfk把这些鸽笼堆了起来,共有\(n\)列,第i列放了\(a_i\)个鸽笼,满足 \(\sum a_i=N+1\). 每当UR结束,管理员们就会按照编号从小到大的顺序回到鸽笼里,每个管理员回来的时候,会先等概率的在所有还有剩余的鸽笼的列中随机一个列,然后住到这列剩下的鸽笼里编号最小的一个中. 现在\(N\)个管理员都回笼了之后,还有一列会空出一个鸽笼.你能对于每一列,求出这

UOJ——【UNR #1】争夺圣杯

1.题意:给一个序列,枚举长度x,然后在这个序列中所有长度为x的区间,我们求出这些区间的最大值之和并取模,最后将所有的异或起来就好啦 2.分析:听说好多人写的O(nlogn) ,特来写一发O(n) 的算法骗访问量 话说这个东西,我们对于每一个点,设这个点的值是max,我们可以求出他影响的所有区间,这个用单调栈解决即可,也就是说求出左边和右边第一个比这个点大的值的位置,设左边那个哪个位置是i,右边那个位置是j,那么我们就能得到这些区间啦,然后我们就可以随便写写就A了 ,这明显是不能AC的,那我们考

大陆27个省级行政区片区数据-基于58同城二手房数据

[数据来源]http://www.58.com城市清单http://www.58.com/changecity.html[结果汇总]数目省自治区份数.城市数.行政区县数.58片区数.数据总条数:27.483.3751.9723.12676行政区县数:58片区数=1:2.59.详情请查阅附件. [特别说明] 暂未爬取直辖市数据. 省份 市 省市数 行政区县 行政区县数 58片区名 片区数 29省汇总 505 3751 9723 安徽 合肥 22 蜀山 11 安徽大学 43 安徽 合肥 22 蜀山

2017-2018年毕业面试总结《一》

2017年刚好是大四,准备实习的日子,开始各种找工作,投简历.面试,四处奔波,幸好在大学期间没有白费日子,出来找工作也是非常的上心,尽管多次面试碰但还是一直没有丧气,留下了不少当时的总结,于是写下分享,为了以后N年后查看,想想那时的自己为了找个实习单位,也是拼了,从学校佛山到广州,再到深圳,只要有面试机会都会去尝试,不管成不成功,都去试下,那时特别希望自己能找份像样点的实习单位,也很渴望能够去到大公司,果然如我所愿,最后去了百度广州分公司,从那里开启了我走向社会的第一份程序员工作,非常怀念那一段

【UOJ#386】【UNR#3】鸽子固定器(贪心)

[UOJ#386][UNR#3]鸽子固定器(贪心) 题面 UOJ 题解 一个不难想到的暴力做法是把东西按照\(s\)排序,这样子我们枚举极大值和极小值,那么我们选择的一定是这一段之间\(v\)最大的那\(m\)个东西. 考虑优化这个过程,我们枚举右端点,左端点向左移动,每次插入一个元素,用堆来维护选择的过程.这样子复杂度可以做到\(O(n^2logn)\). 考虑继续优化这个过程,首先如果右端点一旦被弹出堆这个过程就可以终止了,这个很显然. 通过这个过程,我们也可以明白如果选择的个数不超过\(m

【UOJ#308】【UNR#2】UOJ拯救计划

[UOJ#308][UNR#2]UOJ拯救计划 题面 UOJ 题解 如果模数很奇怪,我们可以插值一下,设\(f[i]\)表示用了\(i\)种颜色的方案数. 然而模\(6\)这个东西很有意思,\(6=2*3\),所以我们只需要考虑其模\(2\)和模\(3\)的结果了. 而最终答案的贡献是\(\sum_{i=1}^k A_{k}^i f[i]\),当\(i\ge 3\)的时候\(6|A_k^i\),所以我们只需要知道\(f[0],f[1],f[2]\)的值. \(f[0]\)的值?当然是\(0\)啊

uoj308 【UNR #2】UOJ拯救计划

传送门:http://uoj.ac/problem/308 [题解] 考虑枚举用了$i$所学校,那么贡献为${k \choose i} * cnt * i!$ 意思是从$k$所选$i$所出来染色,$cnt$为固定颜色顺序的染色方案,$i!$为可以交换学校位置. 考虑当$i \geq 3$的时候,贡献含有模数因子6,所以模6为0,相当于没有贡献. 当$i = 1$,显然只有$m = 0$有贡献. 对于$m = 0$我们特判,答案显然是$K^n$. 剩下$i = 2$的情况,也就是我们要判断答案是不

uoj#213. 【UNR #1】争夺圣杯

http://uoj.ac/problem/209 单调栈求出每个位置x左边第一个大于它的位置L[x]和右第一个不小于它的位置R[x],于是矩形L[x]<=l<=x<=r<=R[x]内的点(l,r)对应的区间[l,r]的最值为x位置的值,这个矩形内的点只对答案数组的二阶差分的四个位置有影响,可以全部统计后再求两次前缀和得到答案. #include<bits/stdc++.h> typedef long long i64; const int N=1e6+7,P=9982

UOJ #218. 【UNR #1】火车管理

http://uoj.ac/problem/218 维护一颗主席树 查询入栈相当于区间修改,弹栈相当于返回历史版本 维护区间求和 原文地址:https://www.cnblogs.com/sssy/p/8322124.html