2018.07.10【省赛模拟】模拟B组

水了暴力的40分,然后只改出了一题。。。
0 【NOI2013模拟】棋盘游戏

有一个N*M的棋盘,初始每个格子都是白色的。
行操作是指选定某一行,将这行所有格子的颜色取反(黑白互换)。
列操作是指选定某一列,将这列所有格子的颜色取反。
XX进行了R次行操作C次列操作(可能对某行或者某列操作了多次),最后棋盘上有S个黑色格子。
问有多少种不同的操作方案。两种操作方案不同,当且仅当对某行或者某列操作次数不同(也就是说与操作的顺序无关)。
方案数可能很大,输出它对10^9+7取模的结果。

题库给的题解:(自己的+听来的理解)
本题是道较简单的组合计数题。(真的吗)
(当某行或某列被操作偶数次时,相当于没有操作,对最终得到的棋盘无影响,所以只有当某行或某列被操作奇数次时,视为对棋盘进行的有效操作)
设有p行被操作了奇数次,有q列被操作了奇数次,
那么黑色格子的数目S=(n-p)q+(m-q)p=mp+nq-2pq(这个可以通过画图很快想到)
若p<>n/2,则q=(S-mp)/(n-2p),(通过这个可以枚举p,计算q,再用p,q得出答案)
当且仅当p,q非负,p<=r且q<=c,r-p,c-q为偶数时,存在满足条件的操作方案。
(辣鸡的我连组合数公式都忘了:C(n,m)表示从n个数中取m个的方案数=n!/【m!(n-m)!】)
方案数 calc(p,q)=C(n,p)*C(m,q)*C((r-p)/2+n-1,n-1)*C((c-q)/2+m-1,m-1).
当p=n/2且S=nm/2时,q为0~min(m,c)的任意整数
方案数 calc2=C(n,p)*C((r-p)/2+n-1,n-1)*C(c+m-1,m-1)
枚举p(p<>n/2),计算出q,将答案加上calc(p,q).
再将答案加上calc2即可.
通过预处理阶乘及其逆元,计算组合数的复杂度可以降至O(1)
(凉凉的我居然不会打逆元,呜呜)
时间复杂度O(n log modulo)

逆元

用于(n/m)% p 时,使计算方便
设m1位m的逆元,那么当p为质数时,(n%p)*(m1%p)%p=(n/m)%p
求逆元常用的有两种方式,运用扩展欧几里得或费马小定理
1.扩展欧几里得

void e_gcd(int a, int b, int &gcd, int &x, int &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        gcd = a;
    }
    else
    {
        e_gcd(b, a % b, gcd, y, x);
        y -= x * (a / b)
    }
}

2.费马小定理

当p为质数时,(n/m)%p=(n*m%p)^(p-2)%p
那么可以用快速幂求解

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const long long N=1000000007;
long long n,m,r,c,s,ans;
long long f[200005];

long long ksm(long long a,long long b){
	long long x,y,d;
	x=1;
	y=a;
	d=b;
	while (d){
		if (d&1) x=(x*y)%N;
		y=(y*y)%N;d>>=1;
	}
	return x;
}

long long C(long long x,long long y){
	if (y==0||x==y) return 1;
	long long ss=f[x]*ksm(f[y]*f[x-y]%N,N-2)%N;
	return ss;
}

int main(){
	scanf("%lld%lld%lld%lld%lld",&n,&m,&r,&c,&s);
	f[0]=f[1]=1;
	for (int i=2;i<=max(n,m)*2;i++) f[i]=f[i-1]*i%N;
	for (int x=0;x<=r;x++)
	if ((r-x)%2==0){			
		if (x*2!=n){
		    if ((s-m*x)%(n-2*x)==0) {
				int y=(long long)(s-m*x)/(n-2*x);
				if (y>=0&&y<=c&&y<=m&&(c-y)%2==0)
					ans=(long long)(ans+(C(n,x)*C(m,y)%N)*
						(C((r-x)/2+n-1,n-1)*
						C((c-y)/2+m-1,m-1)
						%N)%N)%N;
		    }
		} else 
		if (s==n*m/2)
			ans=(long long)(ans+((C(n,x)
			*C((r-x)/2+n-1,n-1)%N)
			*C(c+m-1,m-1))
			%N)%N;
	}	
	printf("%lld",ans);
}

1 【JSOI2013】吃货JYY

世界上一共有N个JYY愿意去的城市,分别从1编号到N。JYY选出了K个他一定要乘坐的航班。除此之外,还有M个JYY没有特别的偏好,可以乘坐也可以不乘坐的航班。
一个航班我们用一个三元组(x,y,z)来表示,意义是这趟航班连接城市x和y,并且机票费用是z。每个航班都是往返的,所以JYY花费z的钱,既可以选择从x飞往y,也可以选择从y飞往x。
南京的编号是1,现在JYY打算从南京出发,乘坐所有K个航班,并且最后回到南京,请你帮他求出最小的花费。

正解:状态压缩DP
啊,不会
题库给的题解:状态压缩 DP。显然,路径经过的点和边形成了一个欧拉图,而每个包含的所有必须经
过的 K 条边和节点 1 的欧拉图也对应着原图若干条本质相同的合法路径。考虑一开始维护
一个连通图,并不断往其中添加新的节点和边。F(U)表示状态为 U 的连通图的最小边权和。
U 是一个三进制数,U 的第 i 位取值分别为 0,1,2,分别表示节点 1 不连通、连通且为奇点,
连通且为偶点。转移则是枚举一个不连通的节点 i,考虑将 i 为与 i 相连的必须经过的边加入
U,分两种情况。一种是 i 通过 K 条边中的某一条与 U 连接,因为 K 条边至少被经过一次,
此时不产生额外代价,直接向新状态转移。一种是 i 通过与 U 中的一个节点 j 的最短路进行
转移,此时产生的代价等于 i,j 的最短路长度,并且节点 i,j 的奇偶性都会改变。
任意两点间的最短路可以通过 floyd 预处理得出。通过 DP 我们得到了形成一些连通图
U 的代价,但这些连通图不一定是欧拉图,但我们可以把图中的奇数点两两匹配,并走一遍
它们之间的最短路,就能够成为欧拉图了。把所有这样的连通图构图的费用加上匹配的最小
费用,取最小值后再加上 K 条边的长度和,即为答案。


2 【NOI2013模拟】坑带的树

首先,先介绍仙人掌树。仙人掌树是一张无向图,但是每个节点最多只会在一个环里面,而且这张图的环全部都是简单环,即A->B->C->A这种。
比如下图就是一颗仙人掌树。
好的,知道了仙人掌树之后,我们现在要计算一个东西。
我们现在已经知道了一个N个节点的仙人掌树,称作为原图。接下来,我们要用1-N的一个排列A[1]-A[N]去变换这棵树,具体的,如果原图中有一条边i-j,那么变换出来的图中必须有一条A[i]-A[j]的边。同样的,如果变换出来的图中有一条A[i]-A[j]的边,那么原图中必有一条i-j的边。(简单而言就是点重新编号)
小A为了超脱宇宙的束缚,必须要知道,有多少种排列,可以使得变换出来的新图和原图是一模一样的,具体的,原图中如果存在一条i-j的边,新图也存在一条i-j的边,新图中存在一条i-j的边,原图中也存在i-j的边。
方案数目答案mod 1000000003。

唉,听了三四遍还是没有懂,感觉码量也会很大,比赛水了暴力20分后就没有再改了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值