【INDEX1】(Indexone.pas/c/cpp Time:1s Memory:256M)
【问题描述】
INDEX 是谁?兄弟,这个问题你如果不知道我就只能怀疑你是从火星来的了。 但是,如果你真的不知道他是谁,那么,你可能和他拥有同一个故乡。 其实当年 INDEX 在火星上有 N 个基友和 M 个妹子,生活真是非常逍遥。他每天都把 基友和妹子排成一队,使得他能够站在最前面,领着他的基友后宫团游街(囧)。 但是,他的妹子们的嫉妒心是很强的,如果两个妹子站在一起,肯定会为 INDEX 吵得 不可开交。同时,INDEX 也是有老婆的人,他身后,也就是队伍的第一个人必须是他的基 友后宫团的团长——他老婆(也就是说,M 个妹子中有一个是他的老婆,为了使题目容易 理解,也就是第一个人已经确定是 M 个妹子中的一个了)。而且,他希望由一个基友来殿后。 现在 INDEX 想知道,他能够排成多少种不同的队伍,使得这个队伍满足他的要求?
【输入】
输入文件名为 Indexone.in。 输入一行包含两个整数 N 和 M。
【输出】
输出文件名为 Indexone.out。 输出一行,表示合法的队伍总数对
【输入输出样例】
Indexone.in
1 1
Indexone.out
1
【数据范围】
对于 30%的数据,保证有1≤N,M≤1000。
对于另外 30%的数据,保证有1≤M≤10。
对于 100%的数据,保证有1≤N,M≤1000000。
【题解】
这个题其实和那个什么01序列差不多,答案:
【代码】
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MOD = 1000000007;
const int size = 1000010;
LL a[size],b[size];
LL n,m,ans=1;
LL ksm(LL,LL,LL);
int main() {
freopen("indexone.in","r",stdin);
freopen("indexone.out","w",stdout);
scanf("%lld%lld",&n,&m);
if(m>n)
return puts("0"),0;
a[0]=1;
for(LL i=1;i<=n;i++)
a[i]=a[i-1]*i%MOD;
b[n]=ksm(a[n],MOD-2,MOD);
b[0]=1;
for(LL i=n-1;i>=1;i--)
b[i]=b[i+1]*(i+1)%MOD;
ans=a[n]*a[n-1]%MOD*b[n-m]%MOD;
printf("%lld\n",ans);
return 0;
}
LL ksm(LL x,LL y,LL Mod) {
x%=Mod;
LL ret=1;
while(y) {
if(y&1)
ret=ret*x%Mod;
x=x*x%Mod;
y>>=1;
}
return ret;
}
【INDEX2】(Indextwo.pas/c/cpp Time:1s Memory:256M)
【问题描述】
故事承接上文。 这事发生在博士还不那么内涵,现哥还不那么傻逼,姜嗲还没开始玩 dota,巨胖才 50Kg 的时候。有一天,INDEX 的老婆再也不能忍受 INDEX 那过分庞大超过一阿伏伽德罗常数的 后宫量,那天夜里,她将 INDEX 绑架到了飞船上,“私奔”到了月球,在《Fly me to the moon》 的歌声中。好美啊! 这个时刻,INDEX 发现有一颗蓝色的星球一直在绕着一颗红色的星球转动。接着,他 又发现,他的故乡火星也一直在绕着这颗红色的星球转动!!!厉害爆了有木有!!!现在,他 的老婆将这颗蓝色星球命名为 A,他们的故乡火星命名为 B,并将他们的轨道平均分成 L 块,形成了 L 块扇形区域吗,并从 0 到 L-1 逆时针标号,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”,不包含双引号。
【输入输出样例】
Indextwo.in
3 1 1 2 2
Indextwo.out
0
【数据范围】
对于 30%的数据,保证有 1≤L≤100。
对于 100%的数据,保证有 1≤L≤1000000,而且 0≤Sa,Sb≤L-1,1≤Va,Vb≤L。
【题解】
我们可以发现问题可以转化为求
可以转化为
此时可以很明显发现用扩展gcd就可以求出一个解,那么求通解就很简单了。而我们只要当中的最小整数解。
【代码】
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
LL l,sa,sb,va,vb;
LL x,y;
void swap(int &a,int &b) {
a^=b;b^=a;a^=b;
}
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-=x*(a/b);
return ret;
}
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)
return puts("0"),0;
LL Gcd=ex_gcd(va-vb,l,x,y);
if((sb-sa)%Gcd!=0)
return puts("Ohahahahahahaha"),0;
LL bd=l/Gcd;
x*=((sb-sa)/Gcd);
x=(x%bd+bd)%bd;
printf("%lld\n",x);
return 0;
}
【INDEX3】(Indexthree.pas/c/cpp Time:1s Memory:256M)
【问题描述】
故事承接上文。 INDEX 回家之后,果断废弃了他的后宫基友团。开始和他老婆移居到农村,在一个 N 行 M 列的土地上,在平面直角座标系中,就是横座标从 1 到 N,纵座标从 1 到 M 的地方上 种植树木。特别的,在原点那里,有一个 INDEX 造的太阳。然而,这次种植的树木名字叫 做超能树,为啥叫超能呢,因为它超需要能量,所以叫做超能树,如果这棵树无法从 INDEX 造的太阳中获得能量,也就是有其它树挡住了它的阳光,它就会死去。一棵树挡住了另一棵 树当且仅当这两棵树与原点三点共线,且一棵树距离原点更近。INDEX 已经种植了在他的 土地上的每个整点上都种植了一棵超能树。INDEX 想知道,有多少树可以活下来?
【输入】
输入文件名为 Indexthree.in。 输入仅一行,包含两个正整数 N 和 M。
【输出】
输出文件名为 Indexthree.out。 输出仅一行,表示最后活下来的树木个数。
【输入输出样例】
Indexthree.in
2 2
Indexthree.out
3
【样例解释】
(2,2)上的树被(1,1)上的树挡住了,所以只有两棵树成活。
【数据范围】
对于 60%的数据,保证有 1≤N,M≤1000。
另外 20%的数据,保证 N=M。
对于 100%的数据,保证有 1≤N,M≤1000000。
【题解】
易知,(x,y) 上的树不被其它树挡住的充要条件是gcd(x,y)=1。
因为若gcd(x,y)=d,d>1,那么 (x,y) 上的树必会被(x/d,y/d) (注:不知为何公式gg了)上的树挡住。
所以,问题转化为:对于给定的整数 a , b,有多少正整数对 (x,y),满足x≤a,y≤b,并且gcd(x,y)=1。
前60分,直接gcd(i,j)==1判断即可(暴力分真多)
后20分,用欧拉函数搞一下就可以了。
最后20分,据说要莫比乌斯反演。(然而并不会)
【代码】
先给上蒟蒻的60分暴力代码
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b) {
return b?gcd(b,a%b):a;
}
LL n,m,ans=0;
int main() {
freopen("indexthree.in","r",stdin);
freopen("indexthree.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(gcd(i,j)==1)
ans++;
}
}
printf("%lld\n",ans);
return 0;
}
总结
这次考试竟然没有炸,真的神啦,会做的竟然没有炸,太神了!!!