1. 程式人生 > >NOIP模擬-----開鎖匠

NOIP模擬-----開鎖匠

題目

經濟危機席捲全球,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

四十分:直接模擬,O(NK)

六十分:可以發現除了最開始的第一次以外一直都是在以N迴圈的,可以預處理出開啟第N扇門的嘗試,再來模擬;

一百分:既然每次迴圈嘗試次數都是一樣的,那我們只用求每N扇門的嘗試和前K%N扇門的嘗試,複雜度O(N)

程式碼

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch;
    while((ch=getchar())<'0'||ch>'9'){;}
    int res=ch-'0';
    while((ch=getchar
())>='0'&&ch<='9') res=res*10+ch-'0'; return res; } int n,k,v[100005],place[100005],first,ans[100005]; long long tot[100005],qfe; int main(){ //freopen("unlock.in","r",stdin); //freopen("unlock.out","w",stdout); n=read(),k=read(); for(int i=1;i<=n;i++) { v[i]=read(); place[
v[i]]=i; } first=place[1]-1; ans[1]=place[1]-place[n]; if(ans[1]<0) ans[1]+=n; for(int i=2;i<=n;i++) { ans[i]=place[i]-place[i-1]; if(ans[i]<0) ans[i]=ans[i]+n; } for(int i=1;i<=n;i++) { tot[i]=tot[i-1]+ans[i]; } int y=k/n; qfe=y*tot[n]+tot[k-y*n]-tot[1]+first; cout<<qfe<<endl; return 0; }