做这题的时候,资格赛已经结束了,不过出于兴趣,就做了一下,虽然没办法提交,但是代码较短,思路还算清晰,所以也贴出来先,标准代码可以参见“其它参考”部分。
要注明的是:这里的代码并没有提交,我不知道答案对错,所以下面的解题思路也是我写这个代码时的思路,不一定正确,如果有错,还请一定指出!多谢!
————————————————————————————————————————————————————————————
题目描述:
时间限制: 1000ms 内存限制: 256MB
在 N 条水平线与 M 条竖直线构成的网格中,放 K 枚石子,每个石子都只能放在网格的交叉点上。问在最优的摆放方式下,最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子。
输入文件包含多组测试数据。
第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。
每组数据为三个用空格隔开的整数 N,M,K。
对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y表示最多能找到的符合条件的长方形数量。所有数据按读入顺序从1开始编号。
1 ≤ T ≤ 100
0 ≤ K ≤ N * M
小数据:0 < N, M ≤ 30
大数据:0 < N, M ≤ 30000
3 3 3 8 4 5 13 7 14 86
Case #1: 5 Case #2: 18 Case #3: 1398
解题思路:
/*
最多长方形的情况就是恰好所有点分别形成边长为1的单位正方形,然后所有单位正方形恰好能组成一个大正方形。
但是有时不会这么“好彩”,可能会出现多出几个点的情况,设多出点的数目为z,假设原本的正方形是a*a,那么就要进行以下检查
1. 多出的点是否能够让正方形变成a*(a+l)的长方形,如果可以那么变成这个长方形,z=z-a*l
2. 检查长方形的长边(a+l)有没有超出最大范围,如果超出,削减至和最大范围一致,然后将多出来的点加到z
3. 多出的点不能够增加长方形,那么就优先全部排到长方形的短边上,如果超出最大范围,则排到长边上
4. 计算长方形个数
但是这里也有个问题,假如n和m非常大,给你21个点,那么排成4*4的长方形后,剩下5个点,那么这5个点应该是拆成4+1,增加一条边,而剩下一个没用的点,还是说拆成3+2,分别排在正方形的两边呢?
我用自己非常屎的数学算了一下,貌似还是应该优先按照4+1的方法,尽量增加长方形长边的长度···
现在忽然又觉得很捶春的是那个检测系统关闭了,让我没办法验证代码,至于参考代码我还没看···迟点看看说不定就有答案,或者别人根本不是用这个方法。
*/
刚刚瞥了一眼发现别人代码短得不行···惭愧啊,然后我比对了一下数据,我的代码是错的,不误人子弟了
注意:
//主要注意的地方就是长方形的边长不能超过最大范围,要作判断
代码:下面这个是错的
#include<stdio.h> #include<algorithm> #include<cmath> using namespace std; int main() { bool ax; int tc; long long i,j,n,m,k,x,y,z,cnt=0; long long ans; scanf("%d",&tc); while(tc--) { ax=false; ans = 0; scanf("%lld%lld%lld",&n,&m,&k); if(n>m) swap(n,m); if(n*n<k) { x=n; y=k/n; z=k-x*y; } else { x=y=sqrt(k); z=k-x*y; y+=(z/x); z%=x; if(y>m) { z+=(y-m)*x; y=m; ax=true; } } //得到长、宽、剩余量,长的一边用y表示 for(i=1;i<x;++i) { for(j=1;j<y;++j) { ans+=(y-j)*(x-i); } } long long tx=2,ty=z; long long tmp=0; for(i=1;i<tx;++i) { for(j=1;j<ty;++j) { tmp+=(ty-j)*(tx-i); } } if(ax) { ans+=tmp*x; } else ans+=tmp*y; printf("Case #%lld: %lld\n",++cnt,ans); } }
其它参考:
//第二题来自 mochavic #include <stdio.h> #include <iostream> #include <algorithm> using namespace std; long long f(long long x){ return x * (x - 1) / 2; } int main(){ long long ans = 0; int T, n, m, k, ri = 1, x, y, z; scanf("%d", &T); while (T--){ scanf("%d%d%d", &n, &m, &k); ans = 0; for (x = 1; x <= n; x++){ y = k / x; z = k % x; if (y + (z?1:0) > m) continue; ans = max(f(x) * f(y) + y * f(z), ans); } for (x = 1; x <= m; x++){ y = k / x; z = k % x; if (y + (z?1:0) > n) continue; ans = max(f(x) * f(y) + y * f(z), ans); } cout << "Case #" << ri++ << ": " << ans << endl; } return 0; }