Codeforces Round #736 (Div. 1) C,D1,D2 题解

C. The Three Little Pigs

题目大概是求:

\[Ans[i]=\sum_{j=1}^n {3j\choose i} \]

首先写成生成函数的形式

\[Ans[i]=[x^i](f^0+f^1+f^2...f^n) \]

其中\(f=(1+x)^3\)

考虑直接算出\(f^0+f^1+f^2...f^n\),显然是一个等比数列\(\frac{f^{n+1}-1}{f-1}\)。直接做一遍多项式长除法就行了。

时间复杂度为\(O(n)\)

顺便说一下多项式长除法有点类似暴力卷积,时间复杂度是\(O(NM)\),本题中除数的次数比较小。

D12. Gregor and the Odd Cows

首先看到内部点可以想到皮克定理:

\[S=A+\frac{I}{2}-1 \]

\(S\)是格点多边形的面积,\(A\)是内部点数量,\(I\)​是边界上点的数量。

证明可以归纳,每次将多边形割掉一个小的三角形,然后证明三角形即可。三角形可以转变成矩形-直角三角形。

题目的限制可以表述成:

\[S\in \mathbb{Z}\\ A=2k+1,(k\in \mathbb{Z}) \]

由于小数部分只可能是\(\frac{I}{2}\)带来的,所以\(S\in \mathbb{Z}\Leftrightarrow I=2k,(k\in \mathbb{Z})\)

然后两边同时\(\times 2\)

\[2S=2A+I-2,(A\mod 2=1,I\mod 2=0)\\ \Rightarrow 2A=2S-I+2\\ \Rightarrow 2S\equiv I\pmod 4\and 2S\equiv 0\pmod 2 \]

然后就转变成面积和边界上的点的两个限制。

段点为\((x_1,y_1),(x_2,y_2)\)的线段整点个数为\(\gcd(|x_1-x_2|,|y_1-y_2|)\)

\(2S\)刚好就是两条边的叉积,由于只关心在\(\mod 4\)下的值,所以可以将坐标\(\mod 4\),同时不改变\(2S\mod 4\),但是会改变\(gcd\)

所以我们可以枚举3个坐标\(\mod 4\)下的值,然后就可直接叉积判断\(2s\)的奇偶性了。

现在只需要在满足\(\mod 4\)的前提下\(I\equiv 2s\)

这里需要分情况讨论(下面把坐标\(\mod 4\)相同的元素看作同一集合):

1 三个属于一个集合:

直接就是\(cnt\choose 3\)​,因为这个时候叉积为0,且\(gcd\)也为0 。

2. 其中两个属于集合\(A\),另一个属于集合\(B\)

可以枚举B中的元素,然后枚举两条边的值。属于一个集合中边的权值\(\mod 4=0\),直接取一个组合数就行了。

3. 属于不同集合

这个时候一定有一条边的权值是偶数。

可以发现若\(i\in A,j\in B\),满足\(\gcd(i,j)\mod 4=0/2\),令\(x=\gcd(i,j)\),则\(\forall_{i\in A,j\in B} \gcd(i,j)=x\)

然后直接枚举不被这条偶边连的集合里的元素并且枚举边权就好了。

时间复杂度:\(O(N^2)\),瓶颈是求两点之间整点个数。

code:

#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<'0'||ch>'9'){
//        ch=getchar();
//    }
//    while(ch>='0'&&ch<='9'){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=6e3+1;
int n,x[MAXN],y[MAXN];
int cnt2[4][4];
int cnt[MAXN][4][4][4];
LL c[MAXN][4];
vector<int> conta[4][4];
int GG[4][4][4][4];
mp operator - (mp A,mp B){
	return II(A.FIR-B.FIR,A.SEC-B.SEC);
}
int operator * (mp A,mp B){
	return A.FIR*B.SEC-A.SEC*B.FIR;
}
int preg[MAXN][MAXN];
int main(){
	rep(i,4) rep(j,4) rep(k,4) rep(y,4) GG[i][j][k][y]=-1;
	scanf("%d",&n);
	rb(i,1,n) scanf("%d%d",&x[i],&y[i]);
	rb(i,1,n) rb(j,1,i) preg[i][j]=preg[j][i]=__gcd(abs(x[j]-x[i]),abs(y[j]-y[i]))&3;
	rb(i,1,n) rb(j,1,n) GG[x[i]&3][y[i]&3][x[j]&3][y[j]&3]=preg[i][j],cnt[i][x[j]&3][y[j]&3][preg[i][j]]++;
	rb(i,1,n) cnt2[x[i]&3][y[i]&3]++,conta[x[i]&3][y[i]&3].PB(i);
	rep(i,MAXN) c[i][0]=1;
	rb(i,1,MAXN-1) rb(j,1,3) (c[i][j]=c[i-1][j-1]+c[i-1][j]);
	LL ans=0;
	rep(ax,4) rep(ay,4)
	rep(bx,4) rep(by,4)
	rep(cx,4) rep(cy,4){
		if(II(ax,ay)<=II(bx,by)&&II(bx,by)<=II(cx,cy)){
			int ary=0;
			mp A,B,C;
			A=II(ax,ay);
			B=II(bx,by);
			C=II(cx,cy);
			ary=abs((A-C)*(B-C));
			if(!(ary&1)){
				int t=ary&3;
				if(A==C){
					ans+=c[cnt2[ax][ay]][3];
				}
				else if(A==B){
					rep(CA,4){
						int CB=(t+4-CA)&3;
						if(CA>CB) continue;
						for(auto it:conta[cx][cy])
						if(CA==CB){
							ans+=c[cnt[it][ax][ay][CA]][2];
						}
						else{
							ans+=cnt[it][ax][ay][CA]*cnt[it][bx][by][CB];
						}
					}
				}
				else if(B==C){
					rep(AC,4){
						int AB=(t+4-AC)&3;
						if(AC>AB) continue;
						for(auto it:conta[ax][ay])
						if(AC==AB){
							ans+=c[cnt[it][cx][cy][AC]][2];
						}
						else{
							ans+=cnt[it][cx][cy][AC]*cnt[it][bx][by][AB];
						}
					}
				}
				else{
					rep(AC,4) rep(AB,4){
						int CB=(t+8-AC-AB)&3;
						if(AC%2==0){
							if(AC==GG[ax][ay][cx][cy]){
								for(auto it:conta[bx][by]){
									ans+=cnt[it][ax][ay][AB]*cnt[it][cx][cy][CB];
								}
							}
						}
						else{
							if(AB%2==0){
								if(AB==GG[ax][ay][bx][by]){
									for(auto it:conta[cx][cy]){
										ans+=cnt[it][ax][ay][AC]*cnt[it][bx][by][CB];
									}
								}
							}
							else{
								if(CB==GG[bx][by][cx][cy]){	
									for(auto it:conta[ax][ay]){
										ans+=cnt[it][bx][by][AB]*cnt[it][cx][cy][AC];
									}
								}
							}
						}
					}
				}
			}
		}
	}
	printf("%lld\n",ans);
	return 0;
}