@description@

给定一个 N*M 的方格,我们通过以下步骤往里面填数:

(1)将所有方格填上 0。

(2)对于 i=1...N,选择一个 ki (0 <= ki <= M) ,给第 i 行的前 ki 个数加一。

(3)对于 j=1...M,选择一个 lj (0 <= lj <= N) ,给第 i 列的前 lj 个数加一。

最终每个方格填着 0, 1 或 2。求最后可以得到的不同填数方案总数 mod 998244353。

Constraints

1≤N,M≤5×10^5

N 与 M 都是整数。

Input

输入形式如下:

N M

Output

输出不同的填数方案 mod 998244353。

Sample Input 1

1 2

Sample Output 1

8

@solution@

见过的最水的AGC的F题,没有之一。

大胆考虑一个 dp:设 dp[i][j] 表示前 i 行,有 j 列的 l >= i。

转移时枚举有 p 列的 l = i,则为了不重复计数,第 i+1 行的 k 除了这 p 列都可以取。

为什么呢?如果不是这 p 列,要么在第 i+1 行之前就出现了断层,此时如果这个位置上为 1 则一定是行的贡献;否则要么延伸到 i+1 以下,此时这个位置就是 2,肯定也是惟一的。

如果是这 p 列,则不难验证一定会重复计数。

发现这个 dp 既过不了,也无法优化。

update in 2019/11/03:评论区有大佬指出,这个dp可以使用多项式求幂进行优化(模数还是998244353这么方便的模数)。

不过因为没有实现过这个优化方法,不知道其效率如何。感觉对于 5*10^5 这么庞大的数据用多项式相关算法还是有点玄。。。

下面的容斥方法感觉还是要简单些的(代码实现上)。

我们发现假如重复计数,则第 i+1 行的 k 与第 j 列的 l 是一定的。

于是我们可以固定这一行一列会导致重复计数,同时去掉这一行一列。

当然还要加回两行两列,减去三行三列。。。

就可以得到我们的容斥式子啦:

\[ans = \sum_{i=0}^{min\{N, M\}}(-1)^i\C_{N}^{i}*C_{M}^{i}*i!*(N+1)^{M-i}*(M+1)^{N-i}
\]

上面那个 dp 可以用来感性理解这个容斥的正确性。

@accepted code@

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 20000000;
const int MOD = 998244353;
int pow_mod(int b, int p) {
int ret = 1;
while( p ) {
if( p & 1 ) ret = 1LL*ret*b%MOD;
b = 1LL*b*b%MOD;
p >>= 1;
}
return ret;
}
int fct[MAXN + 5], ifct[MAXN + 5];
void init() {
fct[0] = 1;
for(int i=1;i<=MAXN;i++)
fct[i] = 1LL*fct[i-1]*i%MOD;
ifct[MAXN] = pow_mod(fct[MAXN], MOD-2);
for(int i=MAXN-1;i>=0;i--)
ifct[i] = 1LL*ifct[i+1]*(i+1)%MOD;
}
int pw1[MAXN + 5], pw2[MAXN + 5];
int main() {
init(); int N, M;
scanf("%d%d", &N, &M);
int ans = 0;
pw1[0] = pw2[0] = 1;
for(int i=1;i<=max(N, M);i++)
pw1[i] = 1LL*pw1[i-1]*(N+1)%MOD, pw2[i] = 1LL*pw2[i-1]*(M+1)%MOD;
for(int i=0,f=1;i<=min(N,M);i++,f=1LL*f*(MOD-1)%MOD) {
int del = 1LL*ifct[N-i]*ifct[M-i]%MOD*ifct[i]%MOD;
del = 1LL*del*pw1[M-i]%MOD*pw2[N-i]%MOD;
ans = (ans + 1LL*f*del)%MOD;
}
printf("%lld\n", 1LL*ans*fct[N]%MOD*fct[M]%MOD);
}

@details@

我现在很后悔当时没有打这一场的 AGC。

独立切出来一道 AGC 的 F 题真的很爽www。

@atcoder - AGC035F@ Two Histograms的更多相关文章

  1. [AGC035F]Two Histograms

    Description 你有一个 \(N\) 行.\(M\) 列的.每个格子都填写着 0 的表格.你进行了下面的操作: 对于每一行 \(i\) ,选定自然数 \(r_i\ (0 ≤ r i ≤ M ) ...

  2. ZROI 暑期高端峰会 A班 Day1 组合计数

    AGC036F Square Constriants 一定有 \(l_i<p_i\le r_i\). 考虑朴素容斥,枚举每个数是 \(\le l_i\) 还是 \(\le r_i\).对于 \( ...

  3. 【AGC035F】Two Histograms

    Problem Description 你有一个 \(N\) 行.\(M\) 列的.每个格子都填写着 0 的表格.你进行了下面的操作: 对于每一行 \(i\) ,选定自然数 \(r_i\) (\(0\ ...

  4. 【AtCoder】AtCoder Grand Contest 035 解题报告

    点此进入比赛 \(A\):XOR Circle(点此看题面) 大致题意: 给你\(n\)个数,问是否能将它们摆成一个环,使得环上每个位置都是其相邻两个位置上值的异或值. 先不考虑\(0\),我们假设环 ...

  5. AtCoder Grand Contest 035

    Preface Atcoder的题都好劲啊,都是我做不动的计数与构造 就当锻炼自己的思维能力了(基本都是bzt教的) A - XOR Circle bzt说这题数据太水了只要判一下所有数异或值是否为\ ...

  6. AtCoder Regular Contest 061

    AtCoder Regular Contest 061 C.Many Formulas 题意 给长度不超过\(10\)且由\(0\)到\(9\)数字组成的串S. 可以在两数字间放\(+\)号. 求所有 ...

  7. AtCoder Grand Contest 001 C Shorten Diameter 树的直径知识

    链接:http://agc001.contest.atcoder.jp/tasks/agc001_c 题解(官方): We use the following well-known fact abou ...

  8. Face recognition using Histograms of Oriented Gradients

    Face recognition using Histograms of Oriented Gradients 这篇论文的主要内容是将Hog算子应用到人脸识别上. 转载请注明:http://blog. ...

  9. 行人检測之HOG特征(Histograms of Oriented Gradients)

    之前的文章行人计数.计次提到HOG特征这个概念,这两天看了一下原版的论文,了解了一下HOG特征的原理,并依据自己的理解将这种方法的流程写了下来,假设有不正确的地方欢迎指正. HOG(Histogram ...

随机推荐

  1. ES6--反引号的使用

    /*动态初始退出登出框话模态框*/ /*动态的初始化退出登陆模态框 反引号ES6语法 * 为什么在使用字符串格式直接创建模态框 * 1.不能在html页面中创建模板,因为如果换一个页面就没有对应的模板 ...

  2. Web App开发注意事项

    1.首先我们来看看webkit内核中的一些私有的meta标签,这些meta标签在开发webapp时起到非常重要的作用 <meta content=”width=device-width, ini ...

  3. img标签中的onerror事件

    img标签中有一个onerror事件.是当我引用的src属性获取不到图片或者网络错误导致无法正常显示我src属性的图片时,显示的提示错误图片或者是可以代替的万能图片. 用法: <img src= ...

  4. SSM三大框架整合教程

    前言 SSM就是Spring+SpringMvc+Mybatis,本文搭建一个基本的ssm框架 本文所有源代码包含jar包下载点击:https://download.csdn.net/download ...

  5. 基于LSTM对西储大学轴承故障进行分析

    这篇文章是小萌新对西储大学轴承故障进行分析,固定特征为故障直径为0.007,电机转速为1797,12k驱动端故障数据(Drive_End)即DE-time.故障类型y值:滚动体故障,内圈故障,3时,6 ...

  6. 命令模式(Command、Recevier、Invoker)(电脑开机命令)

    (将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能.) 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是 ...

  7. Oracle中Function学习2

    上一节说函数 这回聊一下 存储过程:有了上节知识点,对这个也许会一种小感觉.呵呵 过程(存储过程):与过程相比, 存储过程是存在数据库中的一个对象 我主要通过例子来了解 不做多解释 相信你也能明白: ...

  8. linux显示进程的内存映射pmap

    pmap命令可以显示进程的内存映射,使用这个命令可以找出造成内存瓶颈的原因. # pmap -d PID 显示PID为47394进程的内存信息. # pmap -d 47394 输出样例: 47394 ...

  9. Dijkstra,floyd,spfa三种最短路的区别和使用

    这里不列举三种算法的实现细节,只是简单描述下思想,分析下异同 一 Dijkstra Dijkstra算法可以解决无负权图的最短路径问题,只能应付单源起点的情况,算法要求两个集合,开始所有点在第二个集合 ...

  10. 将Factory-boy生成的复杂对象转成dict的方法

    最近在做接口测试,使用Factory-boy来生成接口对象实例,接着将对象转成dict,最后通过requests发送请求. 对象转成dict,目前知道的方法就是object.__dict__ .这个方 ...