[NOIP2017模拟]电影

这篇博客介绍了NOIP2017模拟赛中的一道题目,涉及到寻找满足特定条件的最小面积。通过使用map函数,结合数学比例性质a/rev(a)=rev(b)/b,计算所有符合条件的面积并取最小值。文章提供了样例数据及数据规模,并给出了详细解题思路和代码实现。
摘要由CSDN通过智能技术生成

题目:
这里写图片描述
这里写图片描述

样例数据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;
}

本题结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值