Loading

[Codeforces Round #736 (Div. 2)](https://codeforces.com/contest/1549) E.F1 题解

Codeforces Round #736 (Div. 2) E.F1 题解

比赛总结:这场本来有机会上紫的,结果没开longlong FST 不开longlong见祖宗!! 因为个人习惯,能开int就开int,这个习惯我还会坚持,但是一定要注意longlong

E.The Three Little Pigs 生成函数

显然答案就是求\(\sum_{i=1}^{n-1}\tbinom{3i}{x}\)

组合数实际上就是二项式系数,据此可以容易地构造出

\(ans= [x^k]((1+x)^3 + (1+x)^6...(1+x)^{3n})\)

那么就可以\(\enclose{horizontalstrike}{FFT}\) 注意到这个多项式可以看作首项为\((1+x)^3\),公比\((1+x)^3\)的等比数列 可以直接求和

得到结果为

\[\frac{(1+x)^{3n+3}-(1+x)^3}{x^3+3x^2+3x} \]

观察求和式发现分子一定会被整除,于是直接对上式做长除法即可

代码

int fac[maxn],iv[maxn];
int P[maxn],num[maxn];

inline int C(int n,int m){
	if(n < m) return 0;
	return mul(fac[n],mul(iv[m],iv[n - m]));
}

int main(){
	fac[0] = 1;
	for(int i = 1;i < maxn;i++)
		fac[i] = mul(fac[i - 1],i);
	iv[maxn - 1] = ksm(fac[maxn - 1]);
	for(int i = maxn - 2;i >= 0;i--)
		iv[i] = mul(iv[i + 1],i + 1);

	int n = rd();
	int q = rd();
	
	for(int i = 1;i <= 3 * n + 3;i++){
		num[i] = C(3 * n + 3,i);
		if(i <= 3) sub(num[i],C(3,i)); 
	}	
	
	for(int i = 3 * n + 1;i >= 1;i--){
		P[i] = num[i + 2];
		num[i + 1] = (num[i + 1] - (ll)3 * P[i] % MOD +  MOD) % MOD;
		num[i] = (num[i] - (ll)3 * P[i] % MOD +  MOD) % MOD;
	}

	while(q--){
		int x = rd();
		printf("%d\n",P[x + 1]);	
	}
}

F1.Gregor and the Odd Cows (Easy) Pick定理

题意

给出一个\(n\)多边形,每个点的坐标是偶数,从顶点中选出点构成三角形满足三角形的面积是整数并且三角形内整点个数是奇数

求方案数

分析

从整点、面积等题目条件可以看出用到Pick定理:

对于顶点都是整数的简单多边形

\[A = i + \frac{b}{2} - 1 \]

其中\(A\)是多边形面积,\(i\)是内部格点数,\(b\)是边上格点数

题目给的重要条件就是坐标都是偶数,根据向量叉积计算三角形面积的公式

\[S = \frac{1}{2}\vec{AB} \times \vec{AC} = \frac{1}{2} (x_1y_2-x_2y_1)\times(x_1y3-x_3y1) \]

可以得到\(2|S\)

对Pick定理左右乘2,得到\(2A = 2i+ b-2\) ,因为\(i\)是奇数,从而\(4|2(i-1)\) ,从而有\(2A \equiv b \equiv 0(mod \ 4)\)

这表示如果\(b\)是4的倍数,就能够满足条件

\(b\)的计算可以用熟知结论:两点连线上的整点个数\(b = gcd(|x_2-x_1|,|y_2-y_1|) - 1\)

算上端点的\(1\)的话正好就是gcd

仍然利用\(x,y\)都是偶数的性质可以得到

  • $b\equiv 0 (mod \ 4) \ iff \ x_1\equiv x_2 (mod \ 4)\and y_1\equiv y_2(mod \ 4) $
  • \(b\equiv 2(mod \ 4) \ other \ situations\)

这表示我们只关心\(x,y\)在模4下的值!

于是对坐标都模4,将坐标对存入\(cnt\)数组中计数即可

最后发现问题相当于从本质不同的4个点中找三个点,询问是否合法,暴力即可

代码

ll get(int n,int k){
	if(n < k) return 0;
	if(k == 2) return (ll)n * (n - 1) / 2;
	else return (ll)n * (n - 1) * (n - 2) / 6;
}

int bound(int X1,int Y1,int X2,int Y2){
	if(X1 == X2 && Y1 == Y2)
		return 0;
	return 2;
}

ll cnt[2][2];

int main(){
	int n = rd();
	for(int i = 0;i < n;i++){
		int x = rd();
		int y = rd();
		cnt[(x % 4) / 2][(y % 4) / 2]++;
	}
	ll ans = 0;
	int CNT = 0;
	set<multiset<pii>> st;
	for(int X1 = 0;X1 < 2;X1++){
		for(int Y1 = 0;Y1 < 2;Y1++){
			for(int X2 = 0;X2 < 2;X2++){
				for(int Y2 = 0;Y2 < 2;Y2++){
					for(int X3 = 0;X3 < 2;X3++){
						for(int Y3 = 0;Y3 < 2;Y3++){
							pii p1 = make_pair(X1,Y1);
							pii p2 = make_pair(X2,Y2);
							pii p3 = make_pair(X3,Y3);
							multiset<pii> tmp;
							tmp.insert(p1);
							tmp.insert(p2);
							tmp.insert(p3);
							if(st.count(tmp)) continue;
							st.insert(tmp);				
							int tot = bound(X1,Y1,X2,Y2) + bound(X1,Y1,X3,Y3) + bound(X2,Y2,X3,Y3);
							tot %= 4;
							if(!tot){
								if(X1 == X2 && Y1 == Y2 && X1 == X3 && Y1 == Y3) ans += get(cnt[X1][Y1],3);
								else if(X1 == X2 && Y1 == Y2) ans += get(cnt[X1][Y1],2) * cnt[X3][Y3];
								else if(X2 == X3 && Y2 == Y3) ans += get(cnt[X2][Y2],2) * cnt[X1][Y1];
								else ans += cnt[X1][Y1] * cnt[X2][Y2] * cnt[X3][Y3];
							}
						}
					}
				}
			}
		}
	}
	printf("%lld",ans);
}
posted @ 2021-08-03 12:30  MQFLLY  阅读(95)  评论(0编辑  收藏  举报