NOI.AC 【CSP2019模拟Day 4】排列

目录

      • 题目描述
      • 题解
      • 代码

题目描述

NOI.AC 【CSP2019模拟Day 4】排列_第1张图片

题解

该题极其符合人类思维逻辑,我们一般用两个字来形容这种题“水题”。
在草稿纸上画一下这个序列的样子
k + 1 k + 2 k + 3 ⋯ ⋯ n 1 2 3 ⋯ ⋯ k k+1\quad k+2\quad k+3\quad\cdots\cdots \quad n \quad 1\quad 2 \quad3\quad\cdots\cdots k k+1k+2k+3n123k
我们把一个循环看成许多次跳跃,每次从第 i i i个位置跳到第 a [ i ] a[i] a[i]个位置,规定方向向右。可以发现每一步的跳跃长度是相等的为 k k k,每一个循环独立,并且每一个循环的长度(称其为 c n t cnt cnt)也是相等的(并且在形式上是相同的)。(因为错位后的位置关系是没有改变的)
所以我们只需求出 c n t cnt cnt,答案为 n / c n t n/cnt n/cnt
怎样求 c n t cnt cnt呢。对 70 % 70\% 70%的数据,我们可以暴力的模拟跳跃的过程,最坏情况是 O ( n ) O(n) O(n)的。
对于全部数据(貌似更容易想到这个吧),可以想象跳跃的过程,每次跳 k k k这么长,在一个长度为 n n n的环上跳回原点,跳跃长度为 l c m ( n , k ) lcm(n,k) lcm(n,k),所以 c n t cnt cnt等于跳跃步数为 l c m ( n , k ) / k lcm(n,k)/k lcm(n,k)/k A n s = n / ( l c m ( n , k ) / k ) Ans=n/(lcm(n,k)/k) Ans=n/(lcm(n,k)/k)
整理一下 A n s = ( n ∗ k ) / l c m ( n , k ) = g c d ( n , k ) Ans=(n*k)/lcm(n,k)=gcd(n,k) Ans=(nk)/lcm(n,k)=gcd(n,k)

代码

#include
#include
using namespace std;
const int MAXN=int(1e6+5);
#define int long long
int n,k;
int a[MAXN];
int gcd(int a,int b) {
    return (b==0)?a:gcd(b,a%b);
}
signed main()
{
    scanf("%lld%lld",&n,&k);
    /*
    for(int i=k+1;i<=n;i++)
        a[i-k]=i;
    for(int i=1;i<=k;i++)
        a[n-k+i]=i;
    int st=1,nw=1,cnt=0;
    do {
        cnt++;
        nw=a[nw];
    }while(st!=nw);
    printf("%d\n",n/cnt);
    */
    printf("%lld",gcd(n,k));
}

抱歉,之前被 l o n g   l o n g long\ long long long搞了,就懒得改完了。


T h a n k s Thanks Thanks F o r For For R e a d i n g ! Reading! Reading!

你可能感兴趣的:(考来考去碰运气)