NBUT1225 NEW RDSP MODE I(快速幂,规律):

G - NEW RDSP MODE I

NBUT - 1225

题意:

​ 给你三个数 n , n, n, m m m, x x x。代表刚开始有 1 到 n 1 到n 1n刚好n个数,现在让你将序列变换 m m m次,问你变换 m m m次之后前 x x x个的值;

​ 序列每一次变换的规则:将其中奇数位置的数取出,按顺序放在最后面。

思路:

​ 因为变换的规则比较简单,所以我们可以根据这次位置 计算出 变换前的位置,向上推导 m ​ m​ m次即可,那么我们可以先写出变换公式。

假设位置x变换前在位置last,那么我们不难推出下列公式:

  • 如果 x &lt; = ⌊ n / 2 ⌋ ​ x&lt;=\lfloor n/2 \rfloor​ x<=n/2 则有 l a s t = 2 ∗ x ​ last=2*x​ last=2x

  • 否则 则有 l a s t = 2 ∗ ( x − ⌊ n / 2 ⌋ ) − 1 last=2*(x-\lfloor n/2 \rfloor)-1 last=2(xn/2)1

这样规律显示的不够清楚,我们可以这样写
  • 当n为偶数时候:

    • 如果 x &lt; = n ​ x&lt;=n​ x<=n,则有 l a s t = 2 ∗ x ​ last=2*x​ last=2x.
    • 否则 l a s t = 2 ∗ ( x − n / 2 ) − 1 = 2 ∗ x − n − 1 ​ last=2*(x-n/2)-1=2*x-n-1​ last=2(xn/2)1=2xn1
  • 当n为奇数的时候:

    • 如果 x &lt; = ( n + 1 ) / 2 x&lt;=(n+1)/2 x<=(n+1)/2, 则有 l a s t = 2 ∗ x last=2*x last=2x
    • 否则 l a s t = 2 ∗ ( x − ( n + 1 ) / 2 ) − 1 last=2*(x-(n+1)/2)-1 last=2(x(n+1)/2)1 l a s t = 2 ∗ x − n last=2*x-n last=2xn

​ 那么我们可以将位置 x x x向上推导 m m m次,最后得到的位置就是要求的位置 x x x的值。但是 m m m太大,这种根本不可行,我们现在试图找一个更好的公式。

​ 我们有没有发现一个规律,**当 n ​ n​ n为奇数的时候 l a s t ​ last​ last 可以表示为 l a s t = 2 ∗ x   % n ​ last=2*x\ \%n​ last=2x %n ,(如果 l a s t = 0 ​ last=0​ last=0表示last=n);**那么我们向上求 m ​ m​ m次,则乘以 2 m ​ 2^m​ 2m取余 n ​ n​ n即可 (快速幂不难做到这一点)。但是当 n ​ n​ n位偶数的时候怎么办呢?我们发现当 n ​ n​ n位偶数时 n 个 数 ​ n个数​ n的结果与 n + 1 ​ n+1​ n+1的结果一模一样。

因为第 n + 1 ​ n+1​ n+1个数每次都是最后一个奇数,他总会放在最后面,不影响前 n ​ n​ n个数的相对顺序

​ 所以我们当 n ​ n​ n为偶数时,我们可以把 n + 1 ​ n+1​ n+1变为奇数,然后位置 x ​ x​ x的转换 m ​ m​ m次前的位置为 x ∗ 2 m x*2^m%n+1​ x2m

所以程序思想分下面三步:

  • 如果 n n n为偶数就让 n = n + 1 n=n+1 n=n+1
  • 转换 m m m次后位置 x x x的值为 v a l = x ∗ 2 m val=x*2^m%n val=x2m
  • 如果 v a l val val 0 0 0则输出 n n n,否则输出 v a l val val

代码:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值