CF1775F Laboratory on Pluto - dp - 构造 -

题目链接:https://codeforces.com/contest/1775/problem/F

题解:
首先考虑第一问
考虑将答案的图形补成一个矩形
显然出现凹槽不优,因此可以看成一个矩阵去掉几个角之后的图形
因此补成矩形之后周长仍然不变
注意到补成矩形之后的长和宽相差最多1的时候一定可以取到最优值(长和宽相差越小周长越小)
因此可以枚举,相差1且面积大于 \(n\) 的时候停止即可,注意输出的时候去掉的是个角!

再考虑第二问
考虑如果固定住了一个答案矩阵 \(x\times y\),则必有 \(x\times y \ge n\),剩下的几个格子应该是按照 阶梯型 排列(不然无法保证周长最小)
这就是个划分数的加强版(4个角都需要是阶梯型,且总和是 \(x\times y-n\)
考虑 \(dp[i]\) 表示 \(4\) 个角都是阶梯型,且加起来总和是 \(i\) 的方案数
注意循环顺序!(可以先用高维dp多记几个状态求,也可以这么理解:最外层肯定是最后一个取的值,因为这个是限制。然后再重复 \(dp[i]+=dp[i-t]\) 这种的,第 \(i\) 次重复就代表考虑前\(i\) 个角的阶梯状态)
每次 \(x+1, y-1\) 即可
还有一点就是如果 \(x \neq y\),需要 *2,因为可以旋转

代码:

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;

int n,mod;

void solve1(){
	int a = max((int)sqrt(1.0 * n) - 2, 0), b = a;
	while(1){
		if(a*b >= n)break;
		++ a;
		if(a*b >= n)break;
		++ b; 
	}
	printf("%d %d\n",a,b);
	for(int i=1;i<=a;i++,puts(""))
		for(int j=1;j<=b;j++)
			printf("%c", ".#"[(i-1) * b + j <= n]);
}

int dp[1005];
void solve2(){
	int a = sqrt(n), b = a;
	ll ans=0;
	while(1){
		if(a*b >= n)break;
		++ a;
		if(a*b >= n)break;
		++ b; 
	}
	while(a * b >= n){
		int de = a*b - n;
		ans += 1ll*dp[de] * (1 + (a != b))%mod;
		ans %= mod;
		++ a, -- b;
	}
	printf("%d %d\n",2*(a+b),ans);
}

signed main(){
	int te,ty;
	scanf("%d%d",&te,&ty);
	if(ty == 2){
		scanf("%d",&mod);
		dp[0] = 1;
		for(int t=1;t<=1000;t++)
			for(int j=1;j<=4;j++) 
			for(int i=t;i<=1000;i++)
				(dp[i] += dp[i-t]) %= mod;
	}
	while(te --){
		scanf("%d",&n);
		if(ty == 1)solve1();
		else solve2();
	}

	return 0;
}
posted @ 2023-01-16 20:40  SkyRainWind  阅读(37)  评论(0编辑  收藏  举报