【2018/08/21测试T1】【SDOJ 3432】开锁匠

【题目】

题目描述:

经济危机席卷全球,L 国也收到冲击,大量人员失业。

然而,作为 L 国的风云人物,X 找到了自己的新工作。从下周开始,X 将成为一个酒店的助理锁匠,当然,他得先向部门领导展示他的开锁能力。

领导给了 X 一串钥匙,这串钥匙串在一个大圆环上,每把钥匙有一个编号(1 .. N)。然后蒙上 X 的眼睛并把他带到一个圆形的大房间中。在这个房间中有 N 个上锁的门,用 1 .. N 表示,这串 N 把钥匙每一把正好打开一扇门(钥匙编号和门编号一致就可以打开)。

X 的工作就是打开每扇门。他因为蒙着眼睛,不过可以沿着房间的墙壁移动,不能改变方向,直到他摸着一扇门,然后他会尝试用第一把钥匙(最左边)来打开门,如果钥匙不能打开门,他会将钥匙移到另外一侧(最右边),重复这样直到找到正确的钥匙,当他把所有门打开就结束任务。不过 X 不知道的是,领导并不是测试他开锁能力,而是测试他的耐心,所以领导故意把 X 带到圆形房间,这样 X 每开一扇门后,领导就会在后面悄悄把门再次锁上,这样以来,X 打开最后一扇门后又回到第一扇门然后一直重复下去。不过 X 是一个勤奋和耐心的人,他一直毫无怨言的做着这件事,不说任何抱怨的话,只是在每开一扇门他会默默的统计自己已经错误了多少次,不过慢慢时间太久他的计算能力不足,需要你来帮助他计算错误的次数。

任务:给定数字 k,回答当 X 打开第 k 扇门时,一共错误了多少次?

输入格式:

第一行是 2 个整数 N , K

接下来 N 行,每行包含一个整数 Vi,表示钥匙串从第一把(左侧)到最后一把,第 i 把钥匙的编号。

输出格式:

一个整数,回答第 k 次打开一扇门,已经错误的次数

样例数据:

输入

4 6
4
2
1
3

输出

13

备注:

【样例解释】
打开第1扇门的尝试(1号门):4 2 1 3,错误2次,打开后钥匙排列:1 3 4 2
打开第2扇门的尝试(2号门):1 3 4 2,错误3次,打开后钥匙排列:2 1 3 4
打开第3扇门的尝试(3号门):2 1 3 4,错误2次,打开后钥匙排列:3 4 2 1
打开第4扇门的尝试(4号门):3 4 2 1,错误1次,打开后钥匙排列:4 2 1 3
打开第5扇门的尝试(1号门):4 2 1 3,错误2次,打开后钥匙排列:1 3 4 2
打开第6扇门的尝试(2号门):1 3 4 2,错误3次,打开后钥匙排列:2 1 3 4
总错误13次

【数据规模】
40% 数据:1 ≤ N , K ≤ 1000
另外 60% 数据:1 ≤ K ≤ 50000
100% 数据:1 ≤ N ≤ 100000 , 1 ≤ Vi ≤ N,1 ≤ K ≤ 10^{9}

 

【分析】

我们注意到,面向第 i 扇门时(除了第一次开第一扇门),钥匙最左边的钥匙可以打开第 i - 1 (为 0 时就是 n)扇门,这个时候钥匙 i 的位置到第一个位置的距离就是错误次数,即钥匙 i 与 i - 1 在数组的相对位置就是答案,这个值是可以预处理出来的,由于 n 次开锁后就构成了循环,所以直接用 k 除以 n(k 对 n 取模)就可以快速得到答案

 

【代码】

#include
#include
#include
#define N 100005
using namespace std;
int key[N],miss[N];
int main()
{
//	freopen("unlock.in","r",stdin);
//	freopen("unlock.out","w",stdout);
	int n,k,i,x,up,first;
	long long ans,round=0;
	scanf("%d%d",&n,&k);
	for(i=1;i<=n;++i)
	{
		scanf("%d",&x);
		key[x]=i;
		if(x==1)
		  first=i;
	}
	key[0]=key[n];
	for(i=1;i<=n;++i)
	{
		miss[i]=key[i]-key[i-1];
		if(miss[i]<0)  miss[i]+=n;
		round+=miss[i];
	}
	ans=round*(k/n);
	ans=ans-miss[1]+first-1;
	up=k%n;
	for(i=1;i<=up;++i)
	  ans+=miss[i];
	printf("%lld",ans);
//	fclose(stdin);
//	fclose(stdout);
    return 0;

}

 

你可能感兴趣的:(#,模拟)