数学考试5(test20170325)

【我的疯狂被屠】(Crazy.pas/c/cpp Time:1s Memory:256M)

【问题描述】

我是一个傻×蒟蒻,总是被屠,最近连INDEX都开始屠我了,55555~
我研究了一下每天屠我的人的总数,发现这样一个规律。
首先,每个人都只会屠我一次,然后就不屑于屠我了。第一天有1个人屠了我,第二天有1个人屠了我,但是从第三天开始,之前两天屠我的人会告诉他们的一个朋友(当然是没有屠过我的),让他们来屠我。结果,从某时候起,居然连外星人都不远千里来到地球开始屠我了。
作为一个傻×蒟蒻真diaosi,我知道,如果一天被屠X次,则你的RP会上涨X2点。到今天为止,我已经被屠了 N 天。我想算一算这N天我获得了多少点RP,但是我还得去选取数字,就拜托你了。勇敢的骚年啊快去创造奇迹!

【输入】

输入文件名为crazy.in。
输入一行一个正整数N,表示我已经被屠天数。

【输出】

输出文件名为crazy.out。
输出一行一个整数,代表我获得的RP量,因为数字过大,所以对1000000007取模。

【输入输出样例】
crazy.in
4
crazy.out
15

【样例解释】
第一天被屠1次,第二天被屠1次,第三天被屠2次,第四天被屠3次。总计Rp值为 1+1+4+9=15

【数据范围】

对于20%的数据,保证有 1n20
对于50%的数据,保证有 1n105
对于100%的数据,保证有 1n1015

【题解】

真的被屠了。。。

其实很easy的发现就是有关斐波那契数列的问题

我们可以打表继续发现就是: ni=1Fib2(n)=Fib(n)×Fib(n+1)

那么只要用矩阵 O(logN) 求解。

【代码】
矩阵版

#include <cstdio>
#include <cstring>

#define Rep(i,s,t)  for(int i=s;i<=t;i++)

using namespace std;

typedef long long LL;

LL n,MOD=1000000007;

struct Mat{
    LL m[2][2];
};

Mat I={
    1,1,
    1,0,
};

Mat A={
    1,0,
    0,0,
};

Mat mul(Mat a,Mat b)
{
    Mat c;
    memset(c.m,0,sizeof c.m);
    Rep(i,0,1)  Rep(j,0,1)  Rep(k,0,1)
        c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%MOD;
    return c;
}

Mat pow(Mat a,LL b)
{
    Mat ans=a,p=I;
    while(b)
    {
        if(b & 1)   ans=mul(ans,p);
        p=mul(p,p);
        b>>=1;
    }
    return ans;
}


int main()
{
    freopen("crazy.in","r",stdin);
    freopen("crazy.out","w",stdout);
    scanf("%lld",&n);
    Mat ans=pow(A,n);
    printf("%lld\n",(ans.m[0][0]*ans.m[0][1])%MOD);
    return 0;
}

非矩阵版

#include <cstdio>
#include <cstring>
typedef long long LL;
const int MOD = 1000000007;

LL n;
LL left,right;

void work(LL x);

int main() {
    freopen("crazy.in","r",stdin);
    freopen("crazy.out","w",stdout);
    scanf("%lld",&n);
    work(n+1);
    printf("%lld\n",left*right%MOD);
    return 0;
}

void work(LL x) {
    if(x==1) {
        left=1;right=0;return ;
    }
    if(x==2) {
        left=1;right=1;return ;
    }
    if(x&1) {
        work(x-1);
        left=(left+right)%MOD;right=((left-right)%MOD+MOD)%MOD;
        return ;
    }
    work(x/2);
    LL tmpl=left,tmpr=right;
    left=(tmpl*tmpl%MOD+2*tmpl%MOD*tmpr%MOD)%MOD;
    right=(tmpl*tmpl%MOD+tmpr*tmpr%MOD)%MOD;
}

【我的数字选取】(Lucky.pas/c/cpp Time:1s Memory:256M)

【问题描述】

黑了很多人今天来黑下自己。
其实每个数字都是有灵魂的。譬如说我,能被2整除的数字看起来都有点2,。能被4整除的数字不仅2还一脸死相。能被5整除的数字看起来昨天才哭过。能被7整除的数字,原来就是你把5弄哭的!好吧,蛋疼到这里结束。
其实做数据是很累人的,不管你们信不信,反正我是信了。
每次其实我都想这么出数据。首先决定我今天的幸运数字,然后再选定若干个悲剧数字,一个数字是幸运的定义为能够整除我今天的幸运数字而且不能够整除那若干个悲剧数字,最后选定一个区间 [L,R] ,将这个区间中所有的幸运的数字挑出来。我想知道,我究竟能挑出多少个幸运的数字?
Note:幸运的数字和我今天的幸运数字不是同一个东西。

【输入】

输入文件名为Lucky.in。
第一行4个正整数LN、N、L、R,分别表示我今天的幸运数字、悲剧数字的个数、区间的左界、区间的右界。
第二行包含N个正整数,表示若干个悲剧数字。

【输出】

输出文件名为Lucky.out。
输出仅一行,即我能挑出的幸运的数字的个数。

【输入输出样例】

Lucky.in
2 1 3 4
7

Lucky.out

1

【数据范围】

对于30%的数据,保证有 0n2 1LR105
对于100%的数据,保证有 0n15 1LR1015 ,今天的幸运数字和悲剧数字均可用无符号 32 位整型变量存下。

【题解】

ans =能被今天的幸运数字整除的数的个数-能被今天的幸运数字和至少一个悲剧数字整除的数的个数+能被今天的幸运数字和至少两个悲剧数字整除的数的个数……
因为悲剧数字的个数不超过 15 ,所以可以搜索.

【代码】

#include <cstdio>

typedef long long LL;
const int size = 20;

LL ln,n,l,r;
LL cse[size],num[size],ans,tmp;

LL gcd(LL x,LL y);
void dfs(LL x);

int main() {
    freopen("lucky.in","r",stdin);
    freopen("lucky.out","w",stdout);
    scanf("%lld%lld%lld%lld",&ln,&n,&l,&r);
    for(LL i=1;i<=n;i++)
    scanf("%lld",&num[i]);
    dfs(1);
    printf("%lld\n",ans);
    return 0;
}

LL gcd(LL x,LL y) {
    return y==0 ? x : gcd(y,x%y);
}

void dfs(LL x) {
    if(x==n+1) {
    LL ret = ln;
    for(LL i=1;i<=tmp;i++) {
        ret = ret/gcd(ret,cse[i])*cse[i];
        if(ret>r or ret<0) return ;
    }
    if(tmp&1)
        ans-=r/ret-(l-1)/ret;
    else
        ans+=r/ret-(l-1)/ret;
    return ;
    }
    dfs(x+1);cse[++tmp]=num[x];
    dfs(x+1);tmp--;
}

【我的喂养计划】(Feed.pas/c/cpp Time:1s Memory:256M)

【问题描述】

众所周知,一中2011届信息组有许多胖子。
无奈他们体型过于巨大,于是,他们就请我来节制他们的饮食。我决定,每天喂他们吃粥,这样既可以保证营养,又可以减肥。但是,粥一旦多了,他们就觉得不爽,觉得自己长胖了,粥一旦少了,就不能让他们该题目和考试了。经过长期观察研究,最适合的粥量为N,多一分不行,少一分不干。
悲剧的是,我只有两个勺子,而且它们的容量分别为A和B!(这是感叹号)当然,装粥的那口缸和盛着刚做好的粥的锅是非常大的,你可以将它们的容量视为无穷大。每次,我只能使用一个勺子,用锅里的粥将这个勺子装满,然后倒入缸里面,或者用缸里面的粥将这个勺子倒满,然后放回锅里。对了,每天锅里的粥可以视为无穷大。我比较怕麻烦,希望知道一个最小的操作次数。
当然,他们要我节制他们若干天,所以每天的最适合粥量可能不同。但是,勺子是不会换的(囧)。

【输入】

输入文件名为Feed.in。
输入第一行为两个正整数A和B,分别表示两个勺子的容量。
接下来若干行,每行一个正整数,代表某一天的最适合粥量。

【输出】

输出文件名为Feed.out。
输出若干行,对应于输入中某一最适合粥量的最小操作次数。如果不能刚好达到最适合粥量,那么输出“BeiJu!”,不含引号。

【输入输出样例】

Feed.in
2 4
3
2

Feed.out

BeiJu!
1

【数据范围】

对于50%的数据,保证有 1A,B,N105 ,数据组数等于1。
对于100%的数据,保证有 1A,B,N109 ,数据组数不超过1000。

【题解】

题目要求的即为满足 Ax+By=N 的使 |x|+|y| 最小的整数 x ,y.

用扩展gcd就可以求出特殊解,然后再求出通解。

分以下几种情况分析
这里写图片描述
【代码】

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;

const LL INF = 9223372036854775807LL;
LL a,b,ta,tb,x,y,G,n,ans;

LL ex_gcd(LL a,LL b,LL &x,LL &y);

int main() {
    freopen("feed.in","r",stdin);
    freopen("feed.out","w",stdout);
    scanf("%lld%lld",&a,&b);
    G=ex_gcd(a,b,x,y);
    ta=a/G;tb=b/G;
    while(~scanf("%lld",&n)) {
        if(n%G!=0){
            puts("BeiJu!");
            continue;
        }
        ans=INF;
        LL x0=x*(n/G),y0=y*(n/G),rx,ry;

        rx=x0%tb;ry=y0+ta*(x0/tb);
        ans=min(abs(rx)+abs(ry),ans);

        rx-=tb;ry+=ta;
        ans=min(abs(rx)+abs(ry),ans);

        ry=y0%ta;rx=x0+tb*(y0/ta);
        ans=min(abs(rx)+abs(ry),ans);

        ry-=ta;rx+=tb;
        ans=min(abs(rx)+abs(ry),ans);

        printf("%lld\n",ans);
    }
    return 0;
}

LL ex_gcd(LL a,LL b,LL &x,LL &y) {
    if(b==0) {
        x=1;y=0;
        return a;
    }
    LL ret=ex_gcd(b,a%b,y,x);
    y-=(a/b)*x;
    return ret;
}

总结

论考试不开long long 的后果: 100分直接掉20分。。。

而且打暴力越来越水了。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值