首页 > 其他分享 >P10681 [COTS 2024] 奇偶矩阵 Tablica

P10681 [COTS 2024] 奇偶矩阵 Tablica

时间:2025-01-10 15:13:43浏览次数:1  
标签:奇偶 COTS P10681 s1 s0 int add mul binom

P10681 [COTS 2024] 奇偶矩阵 Tablica

题意

有一个 \(n \times m\) 的 \(01\) 矩阵,问有多少种填 \(01\) 的方式,满足同一行、列恰好有 \(1\) 或 \(2\) 个 \(1\)。

\(n,m \le 3000\)。

思路

首先一个显然的 \(O(nm^2)\) 做法:

设 \(f_{i,s0,s1}\) 表示考虑到第 \(i\) 行,目前有 \(s0\) 列有 \(0\) 个 \(1\),有 \(s1\) 列有 \(1\) 个 \(1\),的方案数。

转移分 \(5\) 种,讨论第 \(i+1\) 行填几个 \(1\),以及在 \(s0\) 还是 \(s1\) 那里选 \(1\)。

就是酱子:

int w = f[i][s0][s1];
if (s0)
	_add(f[i + 1][s0 - 1][s1 + 1], mul(s0, w)),
	_add(f[i + 1][s0 - 1][s1], mul(w, mul(s0, s1)));
if (s1)
	_add(f[i + 1][s0][s1 - 1], mul(s1, w));
if (s0 >= 2)
	_add(f[i + 1][s0 - 2][s1 + 2], mul(w, 1ll * s0 * (s0 - 1) / 2 % mod));
if (s1 >= 2)
	_add(f[i + 1][s0][s1 - 2], mul(w, 1ll * s1 * (s1 - 1) / 2 % mod));

好像 DP 状态不好再减了。

所以考虑不要一行行转移了,直接组合计数。

学习了 yyyyxh 大佬的题解。

枚举有 \(x_1\) 行恰好有 \(1\) 个 \(1\),那么有 \(x_2 = n-x_1\) 恰好有 \(2\) 个 \(1\)。

那么所有列加起来 \(1\) 的个数 \(y_1+2y_2 = x_1+2x_2\),所以可以直接求出 \(y_1,y_2\)。

问题就是有 \(m\) 种球,其中 \(y_1\) 种各有 \(1\) 个,\(y_2\) 种各有 \(2\) 个。有 \(n\) 个桶,其中 \(x_1\) 个容量为 \(1\),\(x_2\) 个容量为 \(2\)。问有多少种放球方式,满足每个桶都放满,且一个桶里不能放两个同一种球。

桶和球的种类都是有编号的,但是编号不影响计数,所以答案乘上组合数 \(\binom{n}{x_1} \binom{m}{y_1}\) 即可。

一个错误答案是 \((y_1+2y_2)!\)。

有两个难处理的问题:

  1. 两个同种球是无序的,容量为 \(2\) 的桶里面两个球也是无序的。
  2. 一个桶不能放两个同种球。

情况 \(1\) 我们就对答案乘上 \(\frac{1}{2^{x_2+y_2}}\)。

情况 \(2\) 考虑容斥。外层只有枚举的 \(O(\min(n,m))\) 复杂度,所以放心容斥。

具体地,就是随便放 \(-\) 钦定一个容量为 \(2\) 的桶放两个一样的球 \(+\) 钦定两个容量为 \(2\) 的桶放两个一样的球……

钦定的方案数就是除去那几个行和列,剩下随便放的方案数。

\[\sum_{k=0}^{\min(x_2,y_2)} \binom{x_2}{k} \binom{y_2}{k} k! (-1)^k \frac{(y_1+2y_2-2k)!}{2^{x_2+y_2-2k}} \]

\(k!\) 是计算每个钦定的桶对应什么种类的球。

这对吗?实际上是错的,如果有两个同种球被放在一个桶里的情况,直接算排列只是多算了 \(1\) 次,而你以为有 \(3\) 次都是多算的。所以当你钦定这两个同种球必须在一个桶里的时候,需要把多减的加回来。就是说容斥要带系数 \(2^k\),体现在分母那里变成 \(2^{x_2+y_2-k}\)。

总的式子就是:

\[\sum_{x_1+x_2=n, y_1+y_2=m, x_1+2x_2=y_1+2y_2} \binom{n}{x_1} \binom{m}{y_1} \sum_{k=0}^{\min(x_2,y_2)} \binom{x_2}{k} \binom{y_2}{k} k! (-1)^k \frac{(y_1+2y_2-2k)!}{2^{x_2+y_2-k}} \]

\(\binom{x_2}{k} \binom{y_2}{k} k! (-1)^k \frac{(y_1+2y_2-2k)!}{2^{x_2+y_2-k}}\) 算出来是小数,很反直觉。大概是容斥容的。

复杂度 \(O(\min(n,m)^2)\)。

code

好难。

#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace hesitate {
	constexpr int N=6e3+7,Max=6e3,mod=1e9+7;
	int add(int a,int b) { return a+b>=mod ? a+b-mod : a+b; }
	void _add(int &a,int b) { a=add(a,b); }
	int mul(int a,int b) { return 1ll*a*b%mod; }
	void _mul(int &a,int b) { a=mul(a,b); }
	int ksm(int a,int b=mod-2) {
		int s=1;
		while(b) {
			if(b&1) _mul(s,a);
			_mul(a,a);
			b>>=1;
		}
		return s;
	}
	int fac[N],ifac[N],mi[N],imi[N];
	void init() {
		fac[0]=mi[0]=1;
		rep(i,1,Max) fac[i]=mul(fac[i-1],i);
		rep(i,1,Max) mi[i]=add(mi[i-1],mi[i-1]);
		ifac[Max]=ksm(fac[Max]);
		per(i,Max-1,0) ifac[i]=mul(ifac[i+1],i+1);
		imi[Max]=ksm(mi[Max]);
		per(i,(Max)-1,0) imi[i]=add(imi[i+1],imi[i+1]);
	}
	int c(int n,int m) { return mul(fac[n],mul(ifac[m],ifac[n-m])); }
	int n,m;
	int ans;
	void main() {
		init();
		sf("%d%d",&n,&m);
		rep(x1,0,n) {
			int x2=n-x1,y2=x1+(x2<<1)-m,y1=m-y2;
			if(y2<0 || y1<0) continue;
			int s=0;
			rep(k,0,min(x2,y2)) {
				int sum= (k&1) ? mod-1 : 1;
				_mul(sum,mul(mul(c(x2,k),c(y2,k)),fac[k]));
				_mul(sum,mul(fac[y1+(y2<<1)-(k<<1)],imi[x2+y2-k]));
				_add(s,sum);
			}
			_mul(s,mul(c(n,x1),c(m,y1)));
			_add(ans,s);
		}
		pf("%d\n",ans);
	}
}
int main() {
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("my.out","w",stdout);
    #endif
	hesitate :: main();
}

标签:奇偶,COTS,P10681,s1,s0,int,add,mul,binom
From: https://www.cnblogs.com/liyixin0514/p/18660665

相关文章

  • 3、多线程-两个线程交替打印 0~100 的奇偶数
    题目两个线程交替打印0~100的奇偶数代码示例usingSystem;usingSystem.Threading;usingSystem.Threading.Tasks;publicclassZeroEvenOdd{ privateintn=100; privateAutoResetEventevenEvent=newAutoResetEvent(false); privateAutoResetEventoddEvent......
  • 1、多线程-打印零与奇偶数
    题目:classZeroEvenOdd{publicZeroEvenOdd(intn){...}//构造函数publicvoidzero(printNumber){...}//仅打印出0publicvoideven(printNumber){...}//仅打印出偶数publicvoidodd(printNumber){...}//仅打印出奇数}相同的一个ZeroE......
  • P11024 [COTS 2020] 定序 Redoslijed 题解
    先把是否有色的约束处理掉。累一个前缀和,对每个位置判一下即可。考察区间覆盖的性质,显然最后一个操作的区间内的颜色一定与其覆盖的颜色相同。考虑从后往前确定操作的顺序,一个操作只要满足这个条件就可以作为当前的最后一个操作,如果有多个满足条件的操作,随便取一个都合法。考虑......
  • 牛客网VL3 奇偶校验
    1.检测一个长比特的中1的奇偶个数时可以使用按位的的异或;异或使用符号^,比较前后两个比特相异为零,相同为一。例如:^3'b110=0;(1^1^0=0)表示有偶数个1      ^3'b100=1;(1^0^0=1)则表示有奇数个11001所以当对一个完整的比特进行异或时,为零则有偶数个1,为一则有奇......
  • 奇偶数
    #include<stdio.h>intmain(void){ intn; inti=0; while(scanf("%d",&n)!=EOF) { intformer[100000]={1}; intlater[100000]={0}; if(n>2&&n%2==0) { printf("Yes"); } else {......
  • 指数的奇偶性由什么决定?
    指数函数的奇偶性由其指数部分和底数的符号共同决定。在数学中,奇函数和偶函数的定义和指数的特性结合在一起,可以帮助我们分析指数函数是否为奇函数或偶函数。下面详细解释指数函数的奇偶性如何判断:1.奇函数和偶函数的定义回顾偶函数:函数(f(x))满足(f(-x)=f(x)),......
  • 数据结构之线性表——LeetCode:328. 奇偶链表,86. 分隔链表,24. 两两交换链表中的节点
    328.奇偶链表题目描述328.奇偶链表给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。请注意,偶数组和奇数组内部的相对顺序应该与输......
  • 判断奇偶数的小妙招
    要判断一个数是奇数还是偶数,一般首先想到的都是对2取余,但其实有更高明的算法。首先咱们要知道一个知识点:偶数的二进制末位为0,奇数的二进制末位为1。这是进位制本身的规则决定的,二进制是“逢二进一”。如果末位为0,说明它“逢”的都是二,没有零头,即它一定能被2整除。同时,如果八......
  • P8734 奇偶覆盖 题解
    Statement矩形面积并,但是覆盖奇数次、覆盖偶数次的面积要分别输出。Solution提供一种不费脑子的做法:首先离散化、扫描线,问题变成维护区间+1-1、询问全局有多少正数是奇数、多少正数是偶数。若去除“正数”的条件,这是很容易用一个标记下传的线段树维护的,区间分别维护0,1个......
  • 并查集——AcWing 239. 奇偶游戏
    目录并查集定义运用情况注意事项解题思路AcWing239.奇偶游戏题目描述运行代码代码思路改进思路并查集定义并查集(DisjointSetUnion,简称DSU),是一种树形的数据结构,常用于处理一些不交集的合并及查询问题。在并查集中,元素被分成多个不相交的集合,每个集合由一个代表......