题目:
样例数据1
输入
2 2 1
输出
1
样例数据2
输入
132 10 35
输出
35
样例数据3
输入
5 18 1000
输出
-1
样例数据4
输入
48 132 235
输出
2442
【数据规模】
对于30%的数据:1<=maxa,maxb<=1000
对于100%的数据:
1<=maxa,maxb<=
105
,1<=w<=
107
分析:这道题要用上map函数(因为它特别好用),具体的用法是:定义map<变量类型, 变量类型>,前一个用作下标(是的,什么类型的都可以做下标,string都可以),后一个用来存储数值。题的思想是先一行一行老实算得到第一次>w的时候,算一次面积,然后把范围缩小(减一列),再算到哪里满足>w,再算面积,这样一直下去就可以得到所有满足的面积大小,取最小值。由a*b=rev(a)*rev(b)推知a/rev(a)=rev(b)/b,本题就是利用这个比例性质计算的。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
#include<map>//用map时要加入这个库
#define inf 100000000000000000LL
using namespace std;
int n,m,w;
long long ans;
struct node
{
int p,q;
friend bool operator < (const node &a,const node &b)
{
if(a.p==b.p)//用来放防止map错误覆盖存储(什么意思就不管了,记着就行,我也很绝望啊)
return a.q<b.q;
return a.p<b.p;
}
};
node A[100010],B[100010];
map <node,int> a,b;//a存每行有多少满足条件的幸运数对,b存每列有多少满足条件的幸运数对
int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;ch>='0'&&ch<='9';ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}
int fan(int x)//反转
{
int a=0;
while(x)
{
a=a*10+x%10;
x=x/10;
}
return a;
}
int gcd(int a,int b)
{
if(!b)
return a;
return gcd(b,a%b);
}
int main()
{
freopen("movie.in","r",stdin);
freopen("movie.out","w",stdout);
ans=inf;
int k,s,t;
node u;
n=getint();m=getint();w=getint();
for(int i=1;i<=max(n,m);++i)//预处理所有数,把每个数与它的反转的比用分数存起来(p分母,q分子)
{
s=i;t=fan(i);
k=gcd(s,t);
s=s/k;t=t/k;//化到最简
A[i].p=s;A[i].q=t;//A存本身除以反转的比值
B[i].p=t;B[i].q=s;//B存这个数需要一个比值怎样的数与它构成幸运数对
}
for(int i=1;i<=n;++i)
a[B[i]]++;//每个列“数”需要怎样的比值,这种需求存在a中,需要相同的就进入了同一个a,这样,在枚举行“数”的时候,a[行“数”的比值]直接就是这一行有多少满足条件的幸运数对
k=0;
int tot=0;
while(w>tot&&k<=m)
{
k++;
if(k>m)
break;
b[B[k]]++;//每个行“数”需要怎样的比值,这种需求存在b中,需要相同的就进入了同一个b,这样,在删列“数”的时候,b[列“数”的比值]直接就是删去这一列所有满足条件的幸运数对
tot+=a[A[k]];//记录到这一行总共有多少满足条件
}
if(k>m)//w大于tot后会先break掉while,所以如果最后while是因为k>m而停止的,说明找到最后都没有w>tot,就是无解
{
printf("-1\n");
return 0;
}
ans=min(ans,1LL*n*k);//到第一次满足的地方先算一次面积,1LL作用是将i*k转化成longlong型
for(int i=n-1;i>=1;--i)//删一列再算到哪里再次满足,满足了又算面积直到算到整个maxa,maxb完,就求到满足要求的面积的最小值
{
a[B[i+1]]--;
tot-=b[A[i+1]];//从后往前删列
while(w>tot&&k<=m)
{
k++;
if(k>m)
break;
b[B[k]]++;
tot+=a[A[k]];
}
if(k>m)
break;
ans=min(ans,1LL*i*k);
}
printf("%I64d\n",ans);
return 0;
}
本题结。