BestCoder#29 HDU5170&&5171

总是有种种原因没能打成,这次的原因是去大地方买衣服去了,没带电脑在身上,昨天晚上十点从外地赶回来补了签到题(= = 莲辉那天在讨论组里面说啥要大数取模的不会就是这道NC题吧- -),刚才把B题写了(最擅长的矩阵快速幂- -)。

GTY's math problem


Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1636    Accepted Submission(s): 298


问题描述
众所周知,GTY是一位神犇,为了更好的虐场,他从来不写数学作业而是去屠题,他的数学老师非常不爽,但由于GTY每次考试都AK,她也不能说什么,有一天老师在黑板上写了四个数——
   
   
    
    a,b,c,d
   
    然后让GTY比较
   
   
    
    ab
   
   
   
   
    
    cd
   
   的大小,由于GTY不屑于虐这道题,就把这个问题交给你了。
输入描述
多组数据(约5000组),每组数据包含4个整数
   
   
    
    a,b,c,d(1a,b,c,d1000)
   
   ,用空格隔开
输出描述
对于每组数据,若
   
   
    
    ab
   
   >
   
   
    
    cd
   
   ,输出”>”, 若
   
   
    
    ab
   
   <
   
   
    
    cd
   
   ,输出”<”, 若
   
   
    
    ab
   
   =
   
   
    
    cd
   
   ,输出”=”
输入样例
2 1 1 2
2 4 4 2
10 10 9 11
输出样例
>
=
<
A题这题- -简直就是高中数学卷选择题前五道送分题的一道题吗,取个对数就OK了,这些数很仁慈的都大于等于1,所以取了对数后的结果也肯定大于等于0,不过要注意精度,一开始没注意跪了一发OTL。。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

const double eps = 1e-10;

int a,b,c,d;

int main()
{
    while(cin>>a>>b>>c>>d)
    {
        if(abs(b*1.0*log(a*1.0)-d*1.0*log(c*1.0))<eps)
        {
            cout<<"="<<endl;
        }
        else
        {
            if(b*1.0*log(a*1.0)-d*1.0*log(c*1.0)>eps)
            {
                cout<<">"<<endl;
            }
            else
            {
                cout<<"<"<<endl;
            }
        }
    }
    return 0;

}

GTY's birthday gift


Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 585    Accepted Submission(s): 103


问题描述
 GTY的朋友ZZF的生日要来了,GTY问他的基友送什么礼物比较好,他的一个基友说送一个可重集吧!于是GTY找到了一个可重集S,GTY能使用神犇魔法k次,每次可以向可重集中加入一个数 
   
   
    
    a+b(a,bS)
   
   ,现在GTY想最大化可重集的和,这个工作就交给你了。
  注:可重集是指可以包含多个相同元素的集合
输入描述
多组数据(约3组),每组数据的第一行有两个数
   
   
    
    n,k(2n100000,1k1000000000)
   
    表示初始元素数量和可使用的魔法数,第二行包含n个数
   
   
    
    a(1ai100000)
   
   表示初始时可重集的元素
输出描述
对于每组数据,模10000007输出可重集可能的最大和。
输入样例
3 2
3 6 2
输出样例
35

B题思路很明显,要取两个数求和然后重新放入这个集合而且要使得集合中的和尽可能的大,那么我们肯定只有在新加进来的这个数中做文章,而新加的数最大,我们需要的就是每次选取当前集合中最大的两个元素进行累加然后放入这个集合中,所以显然有原来的N个元素中假设最大的两个是a和b而且a>=b,那么进行一次操作后把a+b放入集合中,然后下一次操作肯定是选取a+b,a这两个数,很显然这是一个递推式,而K又蛮大,所以就自然想到了矩阵快速幂这东西(好久没写了不过还是能1AOTL)

| 1 1 0 |^k      | F1 = a           |                               |    Fk+1       |

| 1 0 0 |      * |  F2 = b           |--------------------->|    Fk+2        |

| 1 1 1 |         | sum1=a+b   |                              |    sumk+1  |

然后就是把sumk+1和对原集合排好序后的前N-2个元素的和求和后就是答案了OTL,注意取模,不过没啥陷阱- -

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

const long long mod=(long long )(10000007);
long long a[100005];
struct juzhen{

long long m[5][5];

};

juzhen mut(juzhen a,juzhen b)
{
    juzhen c;
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            c.m[i][j]=0;
            for(int k=0;k<3;k++)
            {
                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;

            }
        }
    }
    return c;
}
juzhen pow(juzhen a,long long p)
{
    juzhen res;
    memset(res.m,0,sizeof(res.m));
    for(int i=0;i<3;i++)
    {
        res.m[i][i]=1;
    }
    while(p)
    {
        if(p&1)
            res=mut(a,res);
            a=mut(a,a);
            p>>=1;
    }
    return res;
}

int main()
{
    int n;
    long long k;
    while(cin>>n>>k)
    {
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
        }
        long long sum=0;
        sort(a,a+n);
        long long t=a[n-1]+a[n-2];
        for(int i=0;i<n-2;i++)
        {
            sum+=a[i];
            sum%=mod;
        }
        juzhen res;
        for(int i=0;i<3;i++)
        {
            for(int j=0;j<3;j++)
            {
                res.m[i][j]=1;
            }
        }
        res.m[0][2]=res.m[1][1]=res.m[1][2]=0;
        res=pow(res,k);
        long long ans;
        ans=((res.m[2][0]*a[n-1])%mod+(res.m[2][1]*a[n-2])%mod+(res.m[2][2]*t)%mod)%mod;
        cout<<(ans+sum)%mod<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值