时间限制: 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
#include<stdio.h> #include<math.h> int main() { //freopen("1.txt", "r", stdin); //freopen("2.txt", "w", stdout); int t,n,m,k,n1,m1,left,c=1; scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&m,&k); if(n>m){ n=m+n; m=n-m; n=n-m; }//so cool! //printf("%d %d",n,m); n1=n<sqrt(k)?n:sqrt(k); m1=m; while(n1*m1>k){ m1--; } long long ans=0; long long res=0; while(n1>=2 && m1<=m){ res+=n1*m1*(n1-1)*(m1-1)>>2; left=k-(m1*n1); if(m1<m) res+=m1*left*(left-1)>>1; else res+=n1*left*(left-1)>>1; ans=res>ans?res:ans; res=0; n1--; m1=k/n1; } printf("Case #%d: %lld\n",c,ans); c++; } return 0; }
这题是看了别人的解法才明白的。
t是控制数据组数,n,m是输入的网格的长和宽,注意:长为n-1的长方形长有n条线构成。然后是k,k是在长和宽两条线相交的交点处放的石头的个数,因此k的值是和长宽的线条数有关的。比如:k=6时,k=2*3, k=8时,k=2*4,或k=2*3+2;因此通过(int)sqrt(k),我们可以得到这么多k个石头所形成的长方形中短一条边的线条数n1(当然不是最短,最短为2,我们后面while中当短的边>=2时依次让n1--,判断其他长方形。。)m1是对应n1的长的一边的线条数,它们与k的关系是m1*n1+left=k,left是形成一个长方形后多下点。可见k>=m1*n1.
通过上面我们得到了能够形成的最大的长方形的m1和n1(两边的线条数),它所包含的长方形个数为:在长的线条中选择两条和在宽的线条中选择两条!
C(2,n1)*C(2,m1)。然后就考虑剩下的点,left=k-n1*m1,我们首先考虑将剩下的点加入到较长的边(如果m1<m),因为这样形成的长方形肯定多!,如果加不下,那也没办法只能加到短的边,但是不论加到哪个边上,所最多能多形成的长方形个数为:在多的点里面选择两个(形成一条线),在所加的边的线里面选择一条线,C(1,m1)*C(2,left)(加到长的边m1),n1也一样。
最后递减n1,求出m1,如果n1>=2 && m1<= m,说明还能形成其他长方形和多余的点left,计算,取所能形成的最大的值。