"蔚来杯"2022牛客暑期多校训练营4-H-Wall Builder II
题目大意
给定 T ( 1 ≤ T ≤ 100 ) T(1\le T\le 100) T(1≤T≤100)个 n ( 1 ≤ n ≤ 100 , n 的总和不超过 200 ) n(1\le n\le 100,n的总和不超过200) n(1≤n≤100,n的总和不超过200),表示有 n n n个 1 × 1 1\times 1 1×1的积木, n − 1 n-1 n−1个 1 × 2 1\times 2 1×2的积木······ 2 2 2个 1 × ( n − 1 ) 1\times (n-1) 1×(n−1)的积木, 1 1 1个 1 × n 1\times n 1×n的积木现要求将其全部拼成一个矩形,要求其周长最小,输出周长与每块积木左下角与右上角的坐标。每块积木不可旋转,即只可以横着放。
解题思路
可以发现对于每个
n
n
n,该矩阵面积不变,而
n
n
n的范围十分小,可以枚举矩阵的长和宽,然后判断其是否可实现。
考虑贪心,对于每次搭建,先用可用的最大积木。
代码实现
#include<bits/stdc++.h>
#define f first
#define s second
#define x first
#define y second
#define ll long long
using namespace std;
pair<pair<int,int>,pair<int,int> >a[10005];
ll n,T,b[105];
long long S;
int main(){
cin>>T;
while(T--){
cin>>n;
S=0;
for(int i=1;i<=n;i++)b[i]=n-i+1,S+=b[i]*i;
for(long long i=S/(ll)sqrt(S);i>=1;i--){
for(int j=1;j<=n;j++)b[j]=n-j+1;
if(S%i==0){
ll cnt=n,k=i,sum=0;
a[sum].f.x=a[sum].f.y=a[sum].s.x=a[sum].s.y=0;
while(k){
ll r=S/i,z=min(n,r);
while(z&&r){
while(b[z]&&r-z>=0){
r-=z;
if(r+z==S/i)a[++sum].f.x=i-k,a[sum].f.y=0,a[sum].s.x=i-k+1,a[sum].s.y=a[sum].f.y+z;//直角坐标系没学好想,x,y反了,不过关系不大
else
a[++sum].f.x=i-k,a[sum].f.y=a[sum-1].s.y,a[sum].s.x=i-k+1,a[sum].s.y=a[sum].f.y+z;
b[z]--;
}z=min(r,z-1);
}
if(r)break;
k--;
}
if(k==0){
cout<<(i+S/i)*2<<'\n';
for(int j=1;j<=sum;j++)cout<<a[j].f.y<<' '<<a[j].f.x<<' '<<a[j].s.y<<' '<<a[j].s.x<<'\n';
break;
}
}
}
}
}