• 题解 [PA2019]Trzy kule


    link

    Description

    对于两个长度为 (n)(01)(a_1,a_2,dots,a_n)(b_1,b_2,dots,b_n),定义它们的距离 (d(a,b)=sum_{i=1}^{n}|a_i-b_i|)

    给定三个长度为 (n)(01)(s_1,s_2,s_3) 以及三个非负整数 (r_1,r_2,r_3),问有多少个长度为 (n)(01)(S) 满足 (d(S,s_1)le r_1,d(S,s_2)le r_2,d(S,s_3)le r_3) 这三个不等式中至少有一个成立。

    (1le nle 10^4)

    Solution

    总的来说,这个题目是一个比较有技巧性的题目。

    首先我们可以想到对原问题进行容斥,即我们计算有多少个 (S) 序列满足 (d(S,s_1)>r_1,d(S,s_2)>r_2,d(S,s_3)>r_3),然后再用 (2^n) 减去即可。

    接着,我们可以发现我们可以稍微变化一下,使得相对关系不变且 (s_1) 为全 (1) 序列,那么对于同一个位置 (s_1,s_2,s_3) 就只会有 (4) 种情况:((1,0,0),(1,0,1),(1,1,0),(1,1,1))

    考虑计算每种情况的个数,并且枚举每种情况的位置多少个放 (0),多少个放 (1) 就可以做到 (Theta(n^4))

    考虑到我们可以利用我们已知的信息列不等式,然后我们就只需要枚举两种,剩下的可以预处理求个后缀和就好了。

    复杂度 (Theta(n^2))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 1000000007
    #define MAXN 10005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
    
    char fs[3][MAXN];
    int n,r[3],sum[4],s[3][MAXN],fac[MAXN],ifac[MAXN],f[MAXN][MAXN]; 
    
    int mul (int a,int b){return 1ll * a * b % mod;}
    int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
    int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
    int gcd (int a,int b){return !b ? a : gcd (b,a % b);}
    int qkpow (int a,int b){
    	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
    	return res;
    }
    int binom (int a,int b){return a >= b ? mul (fac[a],mul (ifac[b],ifac[a - b])) : 0;}
    void Add (int &a,int b){a = add (a,b);}
    void Sub (int &a,int b){a = dec (a,b);}
    
    signed main(){
    	read (n);
    	fac[0] = 1;for (Int i = 1;i <= n;++ i) fac[i] = mul (fac[i - 1],i);
    	ifac[n] = qkpow (fac[n],mod - 2);for (Int i = n;i;-- i) ifac[i - 1] = mul (ifac[i],i);
    	for (Int i = 0;i < 3;++ i){
    		read (r[i]),scanf ("%s",fs[i] + 1);
    		for (Int k = 1;k <= n;++ k) s[i][k] = (fs[i][k] - '0');
    	}
    	for (Int k = 1;k <= n;++ k) if (!s[0][k]) s[0][k] ^= 1,s[1][k] ^= 1,s[2][k] ^= 1;
    	for (Int k = 1;k <= n;++ k) sum[s[1][k] << 1 | s[2][k]] ++;
    	for (Int i = 0;i <= sum[2] + sum[3];++ i)
    		for (Int j = -sum[2];j <= sum[3];++ j) if (!(i + j & 1)){
    			int s3 = i + j >> 1,s2 = i - s3;
    			if (0 <= s2 && s2 <= sum[2] && 0 <= s3 && s3 <= sum[3])
    				Add (f[i][j + sum[2]],mul (binom (sum[2],s2),binom (sum[3],s3)));
    		}
    	for (Int i = sum[2] + sum[3];i >= 0;-- i)
    		for (Int j = sum[3];j >= -sum[2];-- j) Add (f[i][j + sum[2]],f[i][j + 1 + sum[2]]);
    	for (Int i = sum[2] + sum[3];i >= 0;-- i)
    		for (Int j = sum[3];j >= -sum[2];-- j) Add (f[i][j + sum[2]],f[i + 1][j + sum[2]]);
    	int ans = 0,all = 1;
    	for (Int i = 1;i <= n;++ i) all = add (all,all);
    	for (Int s0 = 0;s0 <= sum[0];++ s0)
    		for (Int s1 = 0;s1 <= sum[1];++ s1){
    			int v1 = max (0,max (r[0] - s0 - s1,r[1] + s0 + s1 - sum[0] - sum[1]) + 1),
    				v2 = max (-sum[2],r[2] + s0 - s1 - sum[0] - sum[2] + 1);
    			Add (ans,mul (mul (binom (sum[0],s0),binom (sum[1],s1)),f[v1][v2 + sum[2]]));
    		}
    	write (dec (all,ans)),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    字符乱码问题
    一个利用go反向代理解决api转发的例子(go反向代理)
    udp绑定信息
    python3编码转换(字符串/字节码)——Python
    网络UDP——Python
    常用服务器ftp、ssh——Python
    Linux寻找国内镜像源——Python
    常用 Linux 命令的基本使用(二)——Python
    Linux 主要目录速查表——Python
    飞机大战——Python
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/15376183.html
Copyright © 2020-2023  润新知