基础算法测试test20170326

前言

这次考试竟然出现了许多玄学的情况,请听我下面一一列举…

注:这次考试所有的题目均为 时限:1S 空限:256M

1、无聊的军官(officer.pas/c/cpp)

【问题描述】
每个学年的开始,高一新生们都要进行传统的军训。今年有一个军训教官十分奇怪,他为了测试学员们的反应能力,每次吹哨后学员们都会变换位置。每次左数第i位学员都会站到第ai个位置,经过若干次之后,队伍又会回到原来的样子。
你的任务是计算n个人的队伍至少经过多少次之后,队伍恢复到原来样子。
输入officer.in
输入文件的第一行包含一个整数N( 0N10000 ),表示队伍的人数。
接下来N行,每行一个正整数ai表示左起第i个人接下来出现在左起第ai个位置上。
输出officer.out
仅包括一行,一个正整数M,表示军官最少的吹哨次数。
【样例输入】
5
2
3
4
5
1
【样例输出】
5
【数据规模】
对于30%的数据,有 N100
对于100%的数据,有 N10000 ;
对于全部数据,答案在均在64位整数范围之内。

【题解】

这个题目记得好像是一道NOI导刊上的题目(也有可能记错了),总之这道题并不是很难,考场上大家的实际得分也证明如此。

其实这道题目,只需要根据i和ai的关系建立图形,求出整个图中所有的环的长度,再最后求最小公倍数即可。

【代码】

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

typedef long long LL;
const int size = 10000+10;
bool b[size];
LL n,ans,Gcd,step,next[size];

LL gcd(LL a,LL b);
void dfs(LL x);

int main() {
    freopen("officer.in","r",stdin);
    freopen("officer.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    scanf("%lld",&next[i]);
    for(int i=1;i<=n;i++)
    if(!b[i]) {
        step=0; dfs(i);
        if(ans==0) ans = step;
        else {
        Gcd = gcd(ans,step);
        ans=(ans*step)/Gcd;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

inline LL gcd(LL a,LL b) {
 return b==0 ? a : gcd(b,a%b);
}

inline void dfs(LL x) {
 b[x] = true;
 step++;
 if(b[next[x]]) return;
 else dfs(next[x]);
}

2、拯救save.pas/c/cpp

【问题描述】

正义之士被恶魔抓了,被关在小黑屋里,无法继续他的正义事业,你决定去拯救他。
关正义之士的小黑屋迅速被你打开,可是正义之士却被恶魔用一把锁给锁住了。这把锁包含了N个小锁。只有打开前K-2个锁,且锁上第K-1个锁,才能改变第K个锁的状态(打开或锁上该锁),第1个锁可以任意改变状态,当第1个锁锁上时第2个锁就可以改变状态。
为了知道你到底是要留下来开锁,还是“走为上”,你需要知道到底需要多少次操作才能开锁(打开或锁上一把锁算一次操作,只有当N个小锁都被打开进才算开了锁)。

输入save.in
输入文件save.in第一行为一个N(小锁的个数, 1N1000 )。
第二行为n个整数a1,a2,…,an(每个都是0或者1),中间用单个空格隔开。 如果是ai=1,表示第i个锁是锁着的,反之表示该锁已被打开。
输出save.out
输出文件save.out包括一个数,表示最少要操作的次数。

【样例输入】
4
1 0 1 0
【样例输出】
6
【样例说明】

1010111001100100110010000000

【数据规模】

对于40%的数据,有 N30

对于100%的数据,有 N1000 ;

【题解】

这个题目我并没有严格的证明。思路如下

用数学归纳法我们可以知道将数串000…01(一共i个数,前i-1个数都是0,第i个数是1)最后变换成i个0所需要的次数是 2i11

f[i]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值