题目描述

将\(n\times n\)的网格黑白染色,使得不存在任意一行、任意一列、任意一条大对角线的所有格子同色,求方案数对\(998244353\)取模的结果。

输入

一行一个整数\(n\)。

输出

一行一个整数表示答案对\(998244353\)取模的值。

样例

样例输入

3

样例输出

32

数据范围

对于\(100\%\)的数据,\(1\leq n\leq 300\)。

比第一题难了不知道多少……

这种东西怎么看都是容斥嘛。

我们先考虑对角线没有限制的情况:

枚举行和列有多少个是同色的,若行+列是奇数,则减去方案数,若行+列是偶数,则加上方案数,其他没有限制的点任意选,容斥一波即可(注意,若既有行又有列,则只能是同一颜色;但如果只有行或只有列则可以随意指定颜色,方案数应随之变动)。

那么有对角线该怎么办?

仍然容斥,\(0\)条对角线-\(1\)条对角线+\(2\)条对角线即是最终答案。其中\(0\)条对角线就是上述的算法。

考虑\(1\)条对角线的情况,不妨设是主对角线,令\(f_{i,j,k}\)表示考虑到前\(i\)行\(i\)列,选中了\(j\)行\(k\)列的方案数。然后考虑转移到\(i+1\),则枚举选\(0/1\)行,\(0/1\)列,分别转移。但是会存在一个问题,如果既没有选择行又没有选择列,会导致判断\((i,i)\)这个格子可以任选,但事实上主对角线被锁死了,所以要乘上\(\frac{1}{2}\)的系数。最后\(DP\)完后再根据\(j+k\)的奇偶性确定容斥系数,然后再乘上\(2^{(n-j)(n-k)}\)的系数表示未被考虑的格子的方案。

然后考虑\(2\)条对角线的情况,类似\(1\)条对角线,只是变成从中心开始一圈一圈往外\(DP\),讨论的情况更多(并且要特判,奇数的时候两条对角线颜色必须一样,偶数的时候两条对角线颜色不必一样),就没有什么差别了。

\(Code:\)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define mod 998244353
#define inv2 499122177
#define inv16 935854081
int n, f[2][305][305];
int C[305][305], mul[100005];
void Add(int &a, int b){a = (a + b) % mod;}
int Solve0()
{
int ans = 0;
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
{
int k;
if (!i || !j)
k = i ^ j;
else
k = 1;
int x = (n - i) * (n - j) + k;
ans = (ans + (ll)C[n][i] * C[n][j] % mod * mul[x] % mod * (1 - (i + j) % 2 * 2) % mod) % mod;
}
return ans;
}
int Solve1()
{
memset(f, 0, sizeof(f));
int z = 0;
f[0][0][0] = 2;
for (int i = 0; i < n; i++)
{
for (int j = 0; j <= i; j++)
{
for (int k = 0; k <= i; k++)
{
Add(f[z ^ 1][j][k], (ll)f[z][j][k] * inv2 % mod);
Add(f[z ^ 1][j][k + 1], -f[z][j][k]);
Add(f[z ^ 1][j + 1][k], -f[z][j][k]);
Add(f[z ^ 1][j + 1][k + 1], f[z][j][k]);
f[z][j][k] = 0;
}
}
z ^= 1;
}
int ans = 0;
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
Add(ans, (ll)f[z][i][j] * mul[(n - i) * (n - j)] % mod);
return ans;
}
int Solve2()
{
memset(f, 0, sizeof(f));
int z = 0;
if (n & 1)
{
f[0][0][0] = 1;
f[0][0][1] = f[0][1][0] = -2;
f[0][1][1] = 2;
}
else
f[0][0][0] = 2;
for (int k = n & 1; k < n; k += 2)
{
for (int i = 0; i <= k; i++)
{
for (int j = 0; j <= k; j++)
{
Add(f[z ^ 1][i][j], (ll)f[z][i][j] * inv16 % mod);
Add(f[z ^ 1][i + 1][j], -(ll)f[z][i][j] * inv2 % mod);
Add(f[z ^ 1][i][j + 1], -(ll)f[z][i][j] * inv2 % mod);
Add(f[z ^ 1][i + 2][j], f[z][i][j]);
Add(f[z ^ 1][i][j + 2], f[z][i][j]);
Add(f[z ^ 1][i + 2][j + 1], -(ll)f[z][i][j] * 2ll % mod);
Add(f[z ^ 1][i + 1][j + 2], -(ll)f[z][i][j] * 2ll % mod);
Add(f[z ^ 1][i + 1][j + 1], f[z][i][j] * 2ll % mod);
Add(f[z ^ 1][i + 2][j + 2], f[z][i][j]);
f[z][i][j] = 0;
}
}
z ^= 1;
}
int ans = 0;
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
if (!j && !i && (!(n & 1)))
Add(ans, mul[n * (n - 2) + 2]);
else
Add(ans, (ll)f[z][i][j] * mul[(n - i) * (n - j)] % mod);
return ans;
}
int main()
{
scanf("%d", &n);
C[0][0] = 1;
for (int i = 1; i <= n; i++)
{
C[i][0] = 1;
for (int j = 1; j <= i; j++)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
mul[0] = 1;
for (int i = 1; i <= n * n + 1; i++)
mul[i] = mul[i - 1] * 2 % mod;
int ans = Solve0();
ans = (ans - 2ll * Solve1()) % mod;
ans = (ans + Solve2()) % mod;
if (ans < 0)ans += mod;
printf("%d\n", ans);
}

「模拟赛20191019」B 容斥原理+DP计数的更多相关文章

  1. 「模拟赛20191019」A 简单DP

    题目描述 给一个\(n\times m\)的网格,每个格子上有一个小写字母. 对于所有从左上角\((1,1)\)到右下角\((n,m)\)只向下或向右走的路径构成的集合,判断是否存在两条走法不同的路径 ...

  2. 「模拟赛20190327」 第二题 DP+决策单调性优化

    题目描述 小火车虽然很穷,但是他还是得送礼物给妹子,所以他前往了二次元寻找不需要钱的礼物. 小火车准备玩玩二次元的游戏,游戏当然是在一个二维网格中展开的,网格大小是\(n\times m\)的,某些格 ...

  3. 「模拟赛20191019」C 推式子+贪心+树状数组

    题目描述 给定一棵\(n\)个点的有根树,根节点编号为\(1\),点有点权. 定义\(d(v)\)表示\(v\)到\(1\)的路径上的边数. 定义\(f(v,u)\)在\(v<u\)且\(v\) ...

  4. 「模拟赛20181025」御风剑术 博弈论+DP简单优化

    题目描述 Yasuo 和Riven对一排\(n\)个假人开始练习.斩杀第\(i\)个假人会得到\(c_i\)个精粹.双方轮流出招,他们在练习中互相学习,所以他们的剑术越来越强.基于对方上一次斩杀的假人 ...

  5. 「模拟赛20180306」回忆树 memory LCA+KMP+AC自动机+树状数组

    题目描述 回忆树是一棵树,树边上有小写字母. 一次回忆是这样的:你想起过往,触及心底--唔,不对,我们要说题目. 这题中我们认为回忆是这样的:给定 \(2\) 个点 \(u,v\) (\(u\) 可能 ...

  6. 「模拟赛 2018-11-02」T3 老大 解题报告

    老大 题目描述 因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的特色,办公室群被设计成了树形(n 个点 n − 1 条边的无向连通图),由于新建的办公室太大以 ...

  7. 「模拟赛20180406」膜树 prufer编码+概率

    题目描述 给定一个完全图,保证\(w_{u,v}=w_{v,u}\)且\(w_{u,u}=0\),等概率选取一个随机生成树,对于每一对\((u,v)\),求\(dis(u,v)\)的期望值对\(998 ...

  8. 「模拟赛20180307」三元组 exclaim 枚举+树状数组

    题目描述 给定 \(n,k\) ,求有多少个三元组 \((a,b,c)\) 满足 \(1≤a≤b≤c≤n\)且\(a + b^2 ≡ c^3\ (mod\ k)\). 输入 多组数据,第一行数据组数\ ...

  9. 6.28 NOI模拟赛 好题 状压dp 随机化

    算是一道比较新颖的题目 尽管好像是两年前的省选模拟赛题目.. 对于20%的分数 可以进行爆搜,对于另外20%的数据 因为k很小所以考虑上状压dp. 观察最后答案是一个连通块 从而可以发现这个连通块必然 ...

随机推荐

  1. Dynamics CRM 数据数量限制更改

    1.在CRM2016中如果想要导出超过10000记录数据,更新 MaxRecordsForExportToExcel  这个字段的值. SELECT MaxRecordsForExportToExce ...

  2. 【python爬虫】动态html

    一.反爬策略 1.请求头 ——user-agent ——referer ——cookie 2.访问频率限制 ——代理池 ——再用户访问高峰期进行爬取,冲散日志.12-13 7-10 ——设置等待时长. ...

  3. 跨子域的iframe高度自适应

    一.跨子域的iframe高度自适应 比如 'a.jd.com/3.html' 嵌入了 'b.jd.com/4.html',这种跨子域的页面 3.html 1 2 3 4 5 6 7 8 9 10 11 ...

  4. FFT/NTT [51Nod 1028] 大数乘法 V2

    题目链接:51Nod 传送门 没压位,效率会低一点 1.FFT #include <cstdio> #include <cstring> #include <algori ...

  5. 【loj2263】【CTSC2017】游戏

    题目 小\(R\)和小\(B\)一共完了\(n\)局游戏,第一局小\(R\)获胜的概率为\(p_i\),没有平局,对于第$ i $局游戏: 如果第\(i-1\)局游戏小$ R \(获胜,那么第 局游戏 ...

  6. mysql locate()函数

    mysql> select * from test; +----+------------+-------+-----------+ | id | name | score | subject ...

  7. win10照片查看器不能看jpg等格式图片

    1.首先,我们需要使用注册表编辑器来开启Win10系统照片查看器功能,因为其实这个功能是被隐藏了,那么按下Windows徽标键+R键,打开运行命令窗口,输入“regedit”命令. 2.打开注册表编辑 ...

  8. 移动端 - adb shell常见问题汇总

    一.如何执行adb命令? 答:如果没有配置SDK的环境变量的话,那就先用cd命令进入adb所在文件目录(即F:\android-sdk-windows\platform-tools)后,再执行adb命 ...

  9. Server concepts 详解

    server status 是由 vm_state和task_state 计算出来的,vm_state是虚机当前的稳定状态(例如Active, Error),task_state是虚机当前的瞬间状态( ...

  10. 【软工实践】Beta冲刺(2/5)

    链接部分 队名:女生都队 组长博客: 博客链接 作业博客:博客链接 小组内容 恩泽(组长) 过去两天完成了哪些任务 描述 新增修改用户信息.任务完成反馈等功能API 服务器后端部署,API接口的bet ...