Qual_B:长方形

来源:互联网 发布:闪图制作软件下载 编辑:程序博客网 时间:2024/04/30 00:00


Qual_B:长方形

  • 查看
  • 提交
  • 统计
  • 提问
总时间限制:
2000ms
内存限制:
262144kB
描述

在 N 条水平线与 M 条竖直线构成的网格中,放 K 枚石子,每个石子都只能放在网格的交叉点上。问在最优的摆放方式下,最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子。

输入
输入文件包含多组测试数据。
第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。
每组数据为三个用空格隔开的整数 N,M,K。

1 ≤ T ≤ 100
0 ≤ K ≤ N * M
小数据:0 < N, M ≤ 30
大数据:0 < N, M ≤ 30000
输出
对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y表示最多能找到的符合条件的长方形数量。所有数据按读入顺序从1开始编号。
样例输入
33 3 84 5 137 14 86
样例输出
Case #1: 5Case #2: 18Case #3: 1398

抱怨一下:难道每道题目都要纠结一天么。。。~~~~(>_<)~~~~ 只是一道资格赛题目也这么挑战自己。。。

wa点:数据数量级30000^4,即18位,用long long,记得简写哦;

            输出语句两种都可以:

            printf("%lld\n",max_ans);

               or

            cout<<max_ans<<endl;

            其他数据数量级最大为30000^2,即9位,用int即可;

            其他wa点参见注释吧。


思路:公式容易总结 ( a * ( a - 1 ) / 2) *(b *(b-1)/ 2)  +   max(a, b)  * ( r * (r - 1)/ 2 );

           但是如何找到a和b使上式最大。。。。假设a是较小的数,从大到小枚举a,挺笨的方法。

           本来以为可以找到数学方法,但是找到的都是伪命题,网上的参考基本都是从小到大枚举,注意细节!


另:Output Limit Exceeded 一般是程序产生了不必要的输出,也就是一些调试用的语句没删。

br(r1) 2 br(r1) 2 br(r1) 2 br(r1) 2 br(r1) 2 

 i=1 

/*Name: 2013资格赛:长方形 Author: Sincere 2014/03/26*/  #include <iostream>#include <cstdlib> #include <cstdio>#include <cstring>#include <cmath>//算数平方根函数sqrt(double) #define ll long long//简写一下using namespace std;class B{private:int N, M, K;//数量级最高为30000^2,9位,int足够 ll max_ans;//数量级为30000^4,18位,需用long,long public:void initialize();void readCase();ll cal(int);//注意返回类型ll FF(int, int);void computing();void outResult();};void B::initialize(){N = M = K = 0;max_ans= 0;}void B::readCase(){int tmp;cin>>N>>M>>K;if(N>M)//调整M为较大的数 {tmp = N;N = M;M = tmp;}}ll B::cal(int x){//注意返回类型,所有数量级和ans一样的都要用ll型,其他的如此处参数用int型就可 return x*(x-1)/2;}ll B::FF(int i, int j){//计算长方形数目 //printf("%lld %lld\n",cal(i)*cal(j), cal(i)*cal(j) + (j<M? j:i)* cal(K-i*j));//通过打印每轮枚举过程的数据,发现数据时增时减,故不能够根据曲线的升降来判断最值的位置; return cal(i)*cal(j) + (j<M? j:i)* cal(K-i*j);//可以保证j>i,故尽量加列(j<M),若列已满(j==M),加行 }void B::computing(){int q, ii;ll tmp_ans = 0;//tmp_ans的类型之前写成了int,所以一直wa!!!!!! if(M*N == K){//题目不要求K>N*M的情况 max_ans = cal(N)*cal(M);}else{max_ans = 0;q = sqrt(K*1.0);//令i = 较小的数; ii = N < q ? N:q;//不可超出范围 for(int i = ii; i>=2; i--){//i从中间值开始由大到小枚举,j相应地由小到大变化 int j = M<K/i? M:K/i;tmp_ans = FF(i, j);if(tmp_ans > max_ans){//取最大 max_ans = tmp_ans;}/*if(tmp_ans <= max_ans){//如果出现下降趋势,可以判定之后不会出现更大值,可以停止枚举:这是个伪命题,会导致wa break;}*/if(M<=K/i) //若i小到可以使K/i>=M,即若继续i--,j会保持值为M不变,显然目标量不会出现更大的值 break;tmp_ans = 0;//清零 }}}void B::outResult(){printf("%lld\n",max_ans);//cout<<max_ans<<endl;} int main(){B b;int T;cin >> T;int i = 1;while(T--){b.initialize();b.readCase();b.computing();cout<<"Case #"<<i++<<": ";b.outResult();} return 0;}




0 0
原创粉丝点击