2015.9.11模拟赛 codevs 4160【会玩的】

题目描述 Description

hzwer真的很会玩啊…他有一个n*m的方格,每次可以给方格添加一整行或一整列,但是不能删除。现在他想要让总格子数超过k个,但是又想让总格子数尽可能小。请找出这时的n,m。如果有多解,输出任意一种方案。

输入描述 Input Description

一行3个数n,m,k。

输出描述 Output Description

第一行一个数ans,表示此时的方格数。

第二行两个数m’,n’,表示此时的行数列数。如果有多解,输出任意一种方案

样例输入 Sample Input

3 5 18

样例输出 Sample Output

18

3 6

数据范围及提示 Data Size & Hint

对于100%数据,1<=m,n<=10^9,1<=k<=10^12.

题意是给定n,m,k,要求找到a>=n,b>=m,使得a*b>=k且a*b最小。如果有多解,输出a,b字典序最小的方案。

n*m>=k时,可以直接退出

否则n*m<k

考虑固定一个数a,则另一个数最小是k/a.那么可以用(a,k/a)来更新答案。
如果枚举a,那么只要到sqrt(k)即可。因为我们从1到a枚举,如果有k/a<a,那么一定k/a已经被枚举过。这个状态就没有意义了

因此一个一个for到sqrt(k)即可

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<ctime>
 8 #define LL long long
 9 using namespace std;
10 LL n,m,k;
11 bool rev;
12 inline LL read()
13 {
14     LL x=0,f=1;char ch=getchar();
15     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
16     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
17     return x*f;
18 }
19 int main()
20 {
21     n=read();m=read();k=read();
22     if (n>m)swap(n,m),rev=1;
23     if (n*m>=k)
24     {
25         printf("%lld
%lld %lld",n*m,n,m);
26         return 0;
27     }
28     while (1)
29     {
30         bool mrk=0;LL a=0;
31         for (int i=n;i<=sqrt(k);i++)
32           if (k%i==0&&k/i>=m)
33           {
34               mrk=1;
35               a=i;
36               break;
37           }
38         if (mrk)
39         {
40             if (!rev)printf("%lld
%lld %lld",k,a,k/a);
41             else printf("%lld
%lld %lld",k,k/a,a);
42             return 0;
43         }else k++;
44     }
45 }
codevs4160
——by zhber,转载请注明来源
原文地址:https://www.cnblogs.com/zhber/p/4802275.html