分析

因为题目要求最终形状为一个凸包,所以你只要确定了要选哪些向量以及每个向量用几次,最终形成的那个多边形就固定了。

所以只需考虑最终式子是什么,得到 \(\sum_{i=1}^nx_i=0\)\(\sum_{i=1}^ny_i=0\)。然后你画出图形后会发现横纵轴的最长扩展长度就是只为正的 \(x_i\)\(y_i\) 之和,所以我们要求的就是正负 \(x\) 值相等且都小于 \(m\)\(y\) 值亦然。然后发现 \(n\) 很小,\(x_i\)\(y_i\) 也很小,只有 \(m\) 和我们求出来的每个向量选择次数会很大,所以我们考虑用数位 dp 去拆分每个向量的选择次数,在选择过程中维护两个坐标轴的正负值大小关系,和正值总值与 \(m\) 的关系。

由低位向高位传递过程中维护以下几个值:\(p\) 代表到第几位,\(zx\) 代表低位的选择得到的值为正的 \(x_i\) 总和向本位传递的值,\(zy\) 同理,\(hx\) 代表负的 \(x_i\) 向本位传递的值,\(hy\) 同理,\(cx\) 代表低位上为正的 \(x\) 值是否大于 \(m\) 的低位,\(cy\) 同理。每到一层时枚举当前层各个 \(c_i\) 的子集,以 \(s\) 表示,若 \(s\) 二进制下第 \(i\) 位为 \(1\),则说明第 \(i\) 个向量要选 \(2^p\) 个。

在到达第 \(30\) 位时,显然 \(m\) 值是不可能有 \(2^{30}\) 的,所以我们进行判断,首先那四个代表当前位值的数必须为 \(0\)。然后低位的为正的 \(x\)\(y\) 值必须同样小于等于 \(m\),都满足的情况下我们才能返回 \(1\),视为该情况可行。同时我们发现还有一个要求没处理,就是 \(x\)\(y\) 为正为负的值需相等,这样才能回到起点,因此在低位向高位传递时,必须正值负值该位同为 \(1\) 或同为 \(0\) 时才可以向下一层找答案。具体细节可以看代码。

代码

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
inline void read(int &res){
	res=0;
	int f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=(res<<1)+(res<<3)+c-48,c=getchar();
	res*=f;
}
int n,m;
int x[6],y[6];
int f[32][23][23][23][23][2][2];
int check(int x,int y,int z){//m当前位,比较值当前位 
	if(x^y)return x<y?1:0;//若不同,比较当前位的值 
	return z;//若相同,保留低位比较结果 
}
int dp(int p,int zx,int zy,int hx,int hy,int cx,int cy){//题解中说了含义了
	//cx为1代表x和大于m,cy同理 
	if(p==30)return (!zx&&!zy&&!hx&&!hy&&!cx&&!cy);
	if(~f[p][zx][zy][hx][hy][cx][cy])return f[p][zx][zy][hx][hy][cx][cy];
	int d=m>>p&1;//m的当前位,用于后面的比较 
	f[p][zx][zy][hx][hy][cx][cy]=0;
	for(int s=0;s<(1<<n);s++){
		int nwx=zx,nwy=zy,nwhx=hx,nwhy=hy;//存储当前以s的方式选择最终得到怎样的x值和,y值和 
		for(int i=1;i<=n;i++){
			if(s>>(i-1)&1){
				if(x[i]<0)nwhx-=x[i];
				else nwx+=x[i];
				if(y[i]<0)nwhy-=y[i];
				else nwy+=y[i];
			}
		}
		int dqx=nwx&1,dqy=nwy&1,dqhx=nwhx&1,dqhy=nwhy&1;//当前位正负xy值 
		if(dqx==dqhx&&dqy==dqhy){//若该位满足相等条件,向更高位寻找答案 
			f[p][zx][zy][hx][hy][cx][cy]=(f[p][zx][zy][hx][hy][cx][cy]+dp(p+1,nwx>>1,nwy>>1,nwhx>>1,nwhy>>1,check(d,dqx,cx),check(d,dqy,cy)))%mod;
		}
	}
	return f[p][zx][zy][hx][hy][cx][cy];
}
int main()
{
	read(n);read(m);
	for(int i=1;i<=n;i++){
		read(x[i]);read(y[i]);
	}
	memset(f,-1,sizeof(f));
	printf("%d",(dp(0,0,0,0,0,0,0)-1+mod)%mod);
}

posted on 2021-12-16 15:28  漠寒·  阅读(58)  评论(0编辑  收藏  举报