Uva 1591数据挖掘

这道题紫皮书上写的非常的不清楚,无奈只能看原文,然后发现原文也看不懂,就去看了下别人对这道题的理解,然后还是不是太懂,前前后后一共看了三个小时,才发现,紫皮书这个描述真的坑人。

题意:有两个i个元素的数组P和Q,P数据每个数据占Sp个字节,Q数据每个占Sq个字节,然后我们可以根据第i个元素在P中的位置(一个字节算一个位置),推出第i个元素在Q中的位置。这个公式可以表示为

                                      Pi数据的位置/Sp=Qi数据的位置/Sq=i

比如说pi数据在第100个字节,一个p是占5个字节,那pi/p=20,也就是说是第20个元素,假设Q一个元素是占7个字节,那Q第20个元素的位置为20*7=140个字节。

要求:已知元素的个数n和Sq和Sp求储存Q数组所需要的最大的字节K,本来很简单的,

                                                               K=Sp*n/Sq 

就好了,但是。题目说除法太慢了,要我们用另一个公式

                                                  K=(Sp*n+Sp*n<<A)>>B

注意这个公式与上一个公式不等价,就是两个算出来是不一样的(我那时候一直以为是一样的,导致我看了两个小时没看明白)

题目说Q数组储存的空间可以不连续,但不能叠加,也就是说Q储存的最小字节为Sq*n,如果算出来的K大于这个数就是合法的。

然后要我们输出K,A,B的值,A要最小,如果A一样小的情况,输出B最小,那直接写一个循环,A1~32,B1~32暴力枚举就好了,至于为什么是循环到32,个人认为,因为Sq*n(Sq<2^10,n<2^20)最大值是2^30次,而答案肯定大于这个值,但是如果A大于32的话。2^32*2^32次就会超过long long的长度,所以再大没有什么意义了。

接下来上AC代码(我写的不是很好,很多地方都可以优化,参考一下就好。)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

int main()
{
    long long n;
    long long s=0;
    long long i;
    long long j;
    long long a,b;
    long long li=0,lj=0;
    while(scanf("%lld %lld %lld",&n,&a,&b)!=EOF)
    {
        long long m=1;
        m=m<<62;
        int f=0;
        for(i=0;i<=32;i++)
        {
            for(j=0;j<=32;j++)
            {
                s=((n-1)*a+((n-1)*a<<i)>>j)+b;
                if(s>=n*b)
                {
                    if(s<m)
                    {
                        m=s;
                        li=i;
                        lj=j;
                    }
                }
            }
        }
        printf("%lld %lld %lld\n",m,li,lj);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36715504/article/details/81172378