数学考试 3

45 篇文章 0 订阅
7 篇文章 0 订阅

Math_3


INDEX1


【问题描述】

INDEX 是谁?兄弟,这个问题你如果不知道我就只能怀疑你是从火星来的了。
但是,如果你真的不知道他是谁,那么,你可能和他拥有同一个故乡。
其实当年 INDEX 在火星上有 N 个基友和 M 个妹子,生活真是非常逍遥。他每天都把
基友和妹子排成一队,使得他能够站在最前面,领着他的基友后宫团游街(囧) 。
但是,他的妹子们的嫉妒心是很强的,如果两个妹子站在一起,肯定会为 INDEX 吵得
不可开交。
同时,INDEX 也是有老婆的人,他身后,也就是队伍的第一个人必须是他的基友后宫团的团长——他老婆(也就是说, M 个妹子中有一个是他的老婆,为了使题目容易理解, 也就是第一个人已经确定是 M 个妹子中的一个了) 。
而且, 他希望由一个基友来殿后。
现在 INDEX 想知道,他能够排成多少种不同的队伍,使得这个队伍满足他的要求?


【输入】

输入文件名为 Indexone.in。
输入一行包含两个整数 N M


【输出】

输出文件名为 Indexone.out。
输出一行, 表示合法的队伍总数对 1000000007 的模值, 如果不存在何方方案则输出 0


【输入样例】

1 1


【输出样例】

1


【数据范围】

对于 30% 的数据,保证有 1N,M1000
对于另外 30% 的数据,保证有 1M10
对于 100% 的数据,保证有 1N,M1000000


Solution

ans=n!pm1n1 mod p


Code

#include <iostream>
#include <cstdio>

#define LL long long
#define MOD 1000000007

using namespace std;

LL n,m,ans=1;

LL jie[1000010];
LL ni[1000010];

LL power(LL x,LL y,LL p){
    if(y==0)return 1;
    if(y==1)return x%p;
    LL tmp=power(x,y/2,p);
    tmp=tmp*tmp%p;
    if(y&1)tmp=tmp*(x%p)%p;
    return tmp;
}

int main(){

    freopen("indexone.in","r",stdin);
    freopen("indexone.out","w",stdout);

    scanf("%lld%lld",&n,&m);

    if(m>n){printf("0\n");return 0;}

    jie[0]=1;
    for(LL i=1;i<=n;i++)jie[i]=jie[i-1]*i%MOD;

    ni[n]=power(jie[n],MOD-2,MOD);ni[0]=1;
    for(LL i=n-1;i>=1;i--)ni[i]=ni[i+1]*(i+1)%MOD;

    ans=jie[n]*jie[n-1]%MOD*ni[n-m]%MOD;

    printf("%lld\n",ans);

    return 0;
}

INDEX2


【问题描述】

故事承接上文。
这事发生在博士还不那么内涵, 现哥还不那么傻逼, 姜嗲还没开始玩 dota, 巨胖才 50Kg的时候。
有一天, INDEX 的老婆再也不能忍受 INDEX 那过分庞大超过一阿伏伽德罗常数的后宫量, 那天夜里, 她将 INDEX 绑架到了飞船上, “私奔” 到了月球, 在 《Fly me to the moon》的歌声中。
好美啊!
这个时刻,INDEX 发现有一颗蓝色的星球一直在绕着一颗红色的星球转动。接着,他又发现,他的故乡火星也一直在绕着这颗红色的星球转动! ! !厉害爆了有木有! ! !现在,他的老婆将这颗蓝色星球命名为 A ,他们的故乡火星命名为 B,并将他们的轨道平均分成 L 块,形成了 L 块扇形区域,并从 0 L1 逆时针标号, A 星球和 B 星球都是沿逆时针绕红色星球转动。
一开始的时间计算为 0 ,在 0 时刻时, A 处在 Sa 块,B 处在 Sb 块。
A 的移动速度为 Va 块每 INDEX 小时, B 的移动速度为 Vb 块每 INDEX 小时。
INDEX 向她老婆发誓, 他们会在月球上度过一段美好的二人时光, 直到到某个 INDEX 小时整点的钟声敲响时,若星球 A 和星球 B 所在块的编号相同,那么,他们启程返回火星。
思念自己庞大后宫团的 INDEX 想问你,他们启程返回火星的时刻。


【输入】

输入文件名为 Indextwo.in。
输入仅一行,包含五个正整数,分别为 L Sa Sb Va Vb


【输出】

输出文件名为 Indextwo.out
输出仅一行,表示他们启程返回火星的时刻。若永远都不存在那个时刻,请输出“Ohahahahahahaha” ,不包含双引号。


【输入样例】

3 1 1 2 2


【输出样例】

0


【数据范围】

对于 30% 的数据,保证有 1L100
对于 100% 的数据,保证有 1L1000000 ,而且 0Sa,SbL1 1Va,VbL


Solution

问题等价于求

Sa+VaxSb+Vbx (mod l)
的最小正整数解。

SaSb+x(VaVb)=lk

x(VaVb)lk=SbSa

用扩展欧几里得定理即可求出一个解 x0 ,然后得出通解:
x=x0+l/gcd(VaVb,l)t  (tZ)

求出最小正整数解即可。


Code

#include <iostream>
#include <cstdio>

#define LL long long
#define Min(x,y) ((x)<(y)?(x):(y))

using namespace std;

LL l,sa,sb,va,vb;
LL x,y,fx,fy,fxx,fyy;

LL ex_gcd(LL a,LL b,LL &fx,LL &fy){

    if(b==0){fx=1;fy=0;return a;}

    LL fa,fb;
    LL c=ex_gcd(b,a%b,fa,fb);

    fx=fb;
    fy=fa-fb*(a/b);

    return c;
}

int main(){

    freopen("indextwo.in","r",stdin);
    freopen("indextwo.out","w",stdout);

    scanf("%lld%lld%lld%lld%lld",&l,&sa,&sb,&va,&vb);

    if(va<vb){swap(va,vb);swap(sa,sb);}

    if(sa==sb){printf("0\n");return 0;}

    LL Gcd=ex_gcd(va-vb,l,x,y);

    if((sb-sa)%Gcd!=0){printf("Ohahahahahahaha\n");return 0;}

    LL bd=l/Gcd; 

    x*=((sb-sa)/Gcd);

    x=(x%bd+bd)%bd;

    printf("%lld\n",x);

    return 0;

}

INDEX3


【问题描述】

故事承接上文。
INDEX 回家之后,果断废弃了他的后宫基友团。开始和他老婆移居到农村,在一个 N M 列的土地上,在平面直角坐标系中,就是横坐标从 1 N,纵坐标从 1 M 的地方上种植树木。
特别的,在原点那里,有一个 INDEX 造的太阳。
然而,这次种植的树木名字叫做超能树, 为啥叫超能呢, 因为它超需要能量, 所以叫做超能树, 如果这棵树无法从 INDEX 造的太阳中获得能量,也就是有其它树挡住了它的阳光,它就会死去。
一棵树挡住了另一棵树当且仅当这两棵树与原点三点共线,且一棵树距离原点更近。
INDEX 已经种植了在他的土地上的每个整点上都种植了一棵超能树。
INDEX 想知道,有多少树可以活下来?


【输入】

输入文件名为 Indexthree.in。
输入仅一行,包含两个正整数 N M


【输出】

输出文件名为 Indexthree.out。
输出仅一行,表示最后活下来的树木个数。


【输入样例】

2 2


【输出样例】

3


【样例解释】

(2,2) 上的树被 (1,1) 上的树挡住了,所以只有两棵树成活。


【数据范围】

对于 60% 的数据,保证有 1N,M1000
另外 20% 的数据,保证 N=M
对于 100% 的数据,保证有 1N,M1000000


Solution

易知, (x,y) 上的树不被其它树挡住的充要条件是 gcd(x,y)=1
因为若 gcd(x,y)=d d>1 ,那么 (x,y) 上的树必会被 (xd,yd) 上的树挡住。
所以,问题转化为:对于给定的整数 a , b,有多少正整数对 (x,y) ,满足 xa yb ,并且 gcd(x,y)=1
用莫比乌斯反演即可解决,具体实现方法请见我的另一篇博客 Zap


Code

#include <iostream>
#include <cstdio>

#define LL long long
#define Min(x,y) ((x)<(y)?(x):(y))

using namespace std;

LL n,m,ans;

LL prime[1000010];
bool no_prime[1000010];
LL mu[1000010];
LL sum[1000010];

int main(){

    freopen("indexthree.in","r",stdin);
    freopen("indexthree.out","w",stdout);

    scanf("%lld%lld",&n,&m);
    if(n>m)swap(n,m);

    mu[1]=sum[1]=1;
    for(LL i=2;i<=n;i++){
        if(!no_prime[i]){prime[++prime[0]]=i;mu[i]=-1;}
        for(LL j=1;prime[j]*i<=n;j++){
            no_prime[i*prime[j]]=true;
            if(i%prime[j]==0){mu[i*prime[j]]=0;break;}
            mu[i*prime[j]]=-mu[i];
        }
        sum[i]=sum[i-1]+mu[i];
    }

    for(LL i=1,it;i<=n;i=it+1){
        it=Min(n/(n/i),m/(m/i));
        ans=ans+(n/i)*(m/i)*(sum[it]-sum[i-1]);
    }
    printf("%lld\n",ans);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值