G - NEW RDSP MODE I
題意:
給你三個數,。代表剛開始有剛好n個數,現在讓你將序列變換次,問你變換次之後前個的值;
序列每一次變換的規則:將其中奇數位置的數取出,按順序放在最後面。
思路:
因爲變換的規則比較簡單,所以我們可以根據這次位置 計算出 變換前的位置,向上推導次即可,那麼我們可以先寫出變換公式。
假設位置x變換前在位置last,那麼我們不難推出下列公式:
-
如果 則有
-
否則 則有
這樣規律顯示的不夠清楚,我們可以這樣寫
-
當n爲偶數時候:
- 如果,則有 .
- 否則
-
當n爲奇數的時候:
- 如果, 則有
- 否則 即
那麼我們可以將位置向上推導次,最後得到的位置就是要求的位置的值。但是太大,這種根本不可行,我們現在試圖找一個更好的公式。
我們有沒有發現一個規律,**當爲奇數的時候 可以表示爲 ,(如果表示last=n);**那麼我們向上求次,則乘以取餘即可 (快速冪不難做到這一點)。但是當位偶數的時候怎麼辦呢?我們發現當位偶數時的結果與的結果一模一樣。
因爲第個數每次都是最後一個奇數,他總會放在最後面,不影響前個數的相對順序
所以我們當爲偶數時,我們可以把變爲奇數,然後位置的轉換次前的位置爲 。
所以程序思想分下面三步:
- 如果爲偶數就讓
- 轉換次後位置的值爲
- 如果爲則輸出,否則輸出。
代碼:
#include<queue>
#include<iostream>
#include<string.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef pair<int,int> P;
typedef long long ll;
const int maxn=2e4+100;
int t;
ll quickPow(ll a,ll b,ll mod){
ll ans=1ll;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int main()
{
ll n,m,x,ans;
while(cin>>n>>m>>x){
if(n%2==0) n++;
ll mid=quickPow(2,m,n);
for(ll i=1;i<=x;++i){
if(i>1)
cout<<" ";
ans=i*mid%n;
if(ans==0)
cout<<n;
else
cout<<ans;
}
puts("");
}
return 0;
}