题解 图形

传送门
CF1290F

思路很神奇的题

首先一个凸包唯一对应一个向量可重集
于是DP这个可重集

首先这个可重集需要满足这个限制(懒得LaTeX写一遍公式了):
image
然后发现 \(c_i\) 的取值范围太大了没法直接DP,那怎么办呢?

  • 原式形如 \(\sum c_i*x_i \leqslant m\)
    考虑数位DP,从低到高枚举每个二进制位,状压枚举这一位每个 \(c_i\) 的选法
    然后状态就记录此刻这个位上堆叠的进位数量(与联赛T2类似)
    因为是从低到高DP的所以还需要记录一下已经确定的部分是不是大于 \(m\) 的这一部分
    看到求 \(\sum\limits_{i=1}^na_ic_i=X\)\(\{c_i\}\) 的组数,并且 \(n,a_i\) 都很小而 \(X\) 很大的题目可以考虑数位 DP
    貌似可以用这一技巧处理许多 数量 一维很大的情况
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define fir first
#define sec second
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
struct vec{int x, y; double ang;}a[N];
const double pi=acos(-1.0);
const ll mod=998244353;

namespace force{
	int now;
	ll dp[2][550][550];
	void solve() {
		dp[now^1][0][0]=1;
		for (int k=1; k<=n; ++k,now^=1) {
			for (int i=0; i<=m; ++i) {
				for (int j=0,x,y; j<=m; ++j) {
					x=a[k].x+i, y=a[k].y+j;
					if (0<=x&&x<=m&&0<=y&&y<=m) 
						dp[now][x][y]=(dp[now][x][y]+dp[now^1][i][j])%mod;
				}
			}
		}
		printf("%lld\n", dp[now^1][0][0]);
	}
}

namespace task{
	int lim;
	ll dp[30][21][21][21][21][2][2];
	ll dfs(int u, int nx, int px, int ny, int py, bool p, bool q) {
		// cout<<"dfs: "<<u<<' '<<nx<<' '<<px<<' '<<ny<<' '<<py<<' '<<p<<' '<<q<<endl;
		if (u==30) return !nx&&!px&&!ny&&!py&&!p&&!q;
		ll* t=&dp[u][nx][px][ny][py][p][q];
		if (*t!=-1) return *t;
		else *t=0;
		for (int s=0; s<lim; ++s) {
			int tnx=nx, tpx=px, tny=ny, tpy=py, tm=(m>>u)&1;
			for (int i=1; i<=n; ++i) if (s&(1<<(i-1))) {
				(a[i].x<0?tnx:tpx)+=abs(a[i].x);
				(a[i].y<0?tny:tpy)+=abs(a[i].y);
			}
			// cout<<"t: "<<tnx<<' '<<tpx<<' '<<tny<<' '<<tpy<<endl;
			if (!((tnx^tpx)&1) && !((tny^tpy)&1)) *t=(*t+dfs(u+1, tnx>>1, tpx>>1, tny>>1, tpy>>1, (!((tpx^tm)&1))?p:((tpx&1)>tm), (!((tpy^tm)&1))?q:((tpy&1)>tm)))%mod;
		}
		return *t;
	}
	void solve() {
		lim=1<<n;
		memset(dp, -1, sizeof(dp));
		printf("%lld\n", ((dfs(0, 0, 0, 0, 0, 0, 0)-1)%mod+mod)%mod);
		exit(0);
	}
}

signed main()
{
	freopen("shape.in", "r", stdin);
	freopen("shape.out", "w", stdout);
	
	n=read(); m=read();
	for (int i=1,x,y; i<=n; ++i) {
		x=read(); y=read();
		double tem=atan2(y, x);
		if (tem<0) tem=2*pi-fabs(tem);
		a[i]={x, y, tem};
	}
	sort(a+1, a+n+1, [](vec a, vec b){return a.ang<b.ang;});
	// cout<<"a: "; for (int i=1; i<=n; ++i) cout<<"("<<a[i].x<<','<<a[i].y<<")"<<' '; cout<<endl;
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2022-01-11 20:32  Administrator-09  阅读(2)  评论(0编辑  收藏  举报