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;
}