题目链接

https://atcoder.jp/contests/agc039/tasks/agc039_f

题解

又是很简单的F题我不会。。。
考虑先给每行每列钦定一个最小值\(a_i,b_j\),并假设每行每列的最小值是这个数,且每行每列只需要放\(\ge\)这个数的数即可,那么这种情况的价值是\(\prod^n_{i=1}\prod^m_{j=1}\min(a_i,b_j)\), 方案数是\(\prod^n_{i=1}\prod^m_{j=1}(n+1-\max(a_i,b_j))\)
然后我们需要把最小值的限制容斥掉,也就是枚举若干行若干列容斥掉(限制\(+1\)同时系数乘以\(-1\))。
这样的话直接暴力DP就可以解决。设\(f[k][i][j]\)表示当前用\([1,k]\)中的数填满了\(i\)行\(j\)列。转移可以直接枚举不被容斥的行数、不被容斥的列数、容斥的行数、容斥的列数,乘上贡献系数,得到了一个多项式时间复杂度的算法。
但是我们发现这样转移显然很浪费,我们可以把四个变量同时枚举改成分四个阶段依次枚举,这样转移时间复杂度降到了\(O(n)\).(注意因为要保证从小到大填数,所以必须先枚举不被容斥再枚举被容斥)
不过这题还挺卡常的……需要\(O(n^3)\)预处理一下转移系数,详见代码
时间复杂度\(O(n^4)\)
orz myh

代码

#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define riterator reverse_iterator
using namespace std;inline int read()
{int x = 0,f = 1; char ch = getchar();for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}return x*f;
}const int N = 100;
int P;
llong pw[N+3][N*N+3];
llong comb[N+3][N+3];
llong f[2][N+3][N+3];
llong trans[N+3][N+3];
int n,m,p;llong quickpow(llong x,llong y)
{llong cur = x,ret = 1ll;for(int i=0; y; i++){if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}cur = cur*cur%P;}return ret;
}void initmath()
{for(int i=0; i<=N; i++){pw[i][0] = 1ll; for(int j=1; j<=N*N; j++) pw[i][j] = pw[i][j-1]*i%P;}comb[0][0] = 1ll;for(int i=1; i<=N; i++){comb[i][0] = comb[i][i] = 1ll;for(int j=1; j<i; j++) comb[i][j] = (comb[i-1][j]+comb[i-1][j-1])%P;}
}llong updsum(llong &x,llong y) {x = x+y>=P?x+y-P:x+y;}int main()
{scanf("%d%d%d%lld",&n,&m,&p,&P);initmath();int curk = 0; f[0][0][0] = 1ll;for(int k=1; k<=p; k++){curk^=1; memset(f[curk],0,sizeof(f[curk]));for(int j=0; j<=m; j++) for(int ii=0; ii<=n; ii++) trans[j][ii] = pw[k][ii*(m-j)]%P*pw[p-k+1][ii*j]%P;for(int i=0; i<=n; i++){for(int j=0; j<=m; j++){llong x = f[curk^1][i][j]; if(!x) continue;for(int ii=0; ii+i<=n; ii++){updsum(f[curk][i+ii][j],x*comb[i+ii][i]%P*trans[j][ii]%P);}}}curk^=1; memset(f[curk],0,sizeof(f[curk]));for(int i=0; i<=n; i++) for(int jj=0; jj<=m; jj++) trans[i][jj] = pw[k][jj*(n-i)]%P*pw[p-k+1][jj*i]%P;for(int i=0; i<=n; i++){for(int j=0; j<=m; j++){llong x = f[curk^1][i][j]; if(!x) continue;for(int jj=0; jj+j<=m; jj++){updsum(f[curk][i][j+jj],x*comb[j+jj][j]%P*trans[i][jj]%P);}}}curk^=1; memset(f[curk],0,sizeof(f[curk]));for(int j=0; j<=m; j++) for(int ii=0; ii<=n; ii++) trans[j][ii] = pw[k][ii*(m-j)]%P*pw[p-k][ii*j]%P;for(int i=0; i<=n; i++){for(int j=0; j<=m; j++){llong x = f[curk^1][i][j]; if(!x) continue;for(int ii=0; ii+i<=n; ii++){llong y = x*comb[i+ii][i]%P*trans[j][ii]%P;updsum(f[curk][i+ii][j],ii&1?P-y:y);}}}curk^=1; memset(f[curk],0,sizeof(f[curk]));for(int i=0; i<=n; i++) for(int jj=0; jj<=m; jj++) trans[i][jj] = pw[k][jj*(n-i)]%P*pw[p-k][i*jj]%P;for(int i=0; i<=n; i++){for(int j=0; j<=m; j++){llong x = f[curk^1][i][j]; if(!x) continue;for(int jj=0; jj+j<=m; jj++){llong y = x*comb[j+jj][j]%P*trans[i][jj]%P;updsum(f[curk][i][j+jj],jj&1?P-y:y);}}}}printf("%lld\n",f[curk][n][m]);return 0;
}

AtCoder AGC039F Min Product Sum (容斥原理、组合计数、DP)相关推荐

  1. Educational Codeforces Round 81 (Rated for Div. 2) F.Good Contest \ 洛谷 划艇 组合 计数dp

    cf传送门 P3643 [APIO2016]划艇 文章目录 题意: 思路: 题意: aia_iai​在[li,ri][l_i,r_i][li​,ri​]等概率随机选一个数,求aaa数组不增的概率. 思 ...

  2. bzoj2111,P2606-[ZJOI2010]排列计数【Lucas,组合计数,dp】

    正题 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2111 https://www.luogu.org/problem/P2606 题 ...

  3. 《算法竞赛进阶指南》数论篇(3)-组合计数,Lucas定理,Catalan数列,容斥原理,莫比乌斯反演,概率与数学期望,博弈论之SG函数

    文章目录 组合计数 例题:Counting swaps Lucas定理 Cnm≡Cnmodpmmodp∗Cn/pm/p(modp)C_n^m\equiv C_{n\ mod\ p}^{m\ mod\ ...

  4. 解题报告(五)组合计数(ACM / OI)超高质量题解

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  5. 基础组合计数常用的概念和方法总结

    基础组合计数常用的概念和方法总结 一.组合计数中的基本概念与性质 1.排列 定义 性质 2.组合 定义 性质 二.组合计数中的一些常用技巧 1.容斥原理 定义 公式 2.捆绑与插空法 捆绑法 插空法 ...

  6. 数学知识——组合计数

    组合计数 文章目录 组合计数 概述 动态规划 牡牛和牝牛 思路 代码 隔板法 方程的解 思路 代码 序列统计 思路 代码 加法 & 乘法原理 加法原理 乘法原理 车的摆放 思路 代码 容斥原理 ...

  7. 解题报告(二)E、(BZOJ3513) [MUTC2013] idiots(生成函数 + FFT + 组合计数)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  8. 数据结构之线段树Ⅴ——(李超线段树)Robot,Product Sum,Building Bridges,Jump mission

    文章目录 Robot Product Sum Building Bridges Jump mission Robot BZOJ3938 机器人每次一旦改变速度,直到下一次改变速度为止 这一时间段内机器 ...

  9. 学组合数学心得与题解(一)——组合计数

    今天我在某网站上稍微学习了一下组合数学,准确来讲,今天就看了看组合计数.像一些弱智的排列数.组合数大家肯定在小学奥数就已经精通了(只有我这种蒟蒻忘的精光).当然,博主比较菜,连二项式定理.帕斯卡恒等式 ...

最新文章

  1. Java线程池使用与原理
  2. 局域网连接其他机器命令_弱电工程师必备技能,PING命令使用方法大全
  3. 每日一题(开开森森学前端之变量与函数)
  4. 【数学基础】一份非常适合人工智能学习的高等数学基础材料中文版 (国内教材精华)...
  5. 牛客练习赛25 B-最长区间
  6. 您如何使用硒来计算自动化测试的投资回报率?
  7. 【★原创★】夜晚,不要让电白白流失!
  8. 用mysql制作一个登录_连接数据库制作一个简单的登入页面1
  9. php实现读写ic卡,diy用PIC单片机实现的IC卡读写器
  10. 怎样HTML做图片画廊,42个jQuery图片画廊插件
  11. Luyten反编译工具
  12. java html模板_Java实现静态页面模板替换内容代码
  13. 详解智慧城市排水管理系统整体方案
  14. 数字信号处理中均值、均方值、均方差、均方根值、均方误差、均方根误差、方差、协方差、标准差对比分析及统计学意义
  15. 手机H5如何对接支付宝登陆授权以及支付(H5网站支付)
  16. WebStorm使用-显示隐藏文件
  17. 九连环 C语言递归代码
  18. STM32WB55使用————Zigbee信息收发
  19. Enhanced Assertions
  20. java开发工程师面试自我介绍_Java程序员如何进行自我介绍

热门文章

  1. [MATLAB粒子模拟笔记]差分泊松方程求静电场分布
  2. 第01课:深度学习概述
  3. 就在刚刚!吴恩达的这门新课程终于开放注册了
  4. python内置函数源码_如何查看python内置函数源码
  5. python2:function
  6. VTK修炼之道51:图形基本操作进阶_连通区域分析
  7. BUUCTF-Reverse:[GKCTF2020]Check_1n
  8. Socket is closed 可能原因
  9. python基础——迭代器与生成器
  10. Java多线程同步Synchronized深入解析