HDU 4259 Double Dealing 【离散数学】

Problem Description
Take a deck of n unique cards. Deal the entire deck out to k players in the usual way: the top card to player 1, the next to player 2, the k th to player k, the k+1 st to player 1, and so on. Then pick up the cards – place player 1′s cards on top, then player 2, and so on, so that player k’s cards are on the bottom. Each player’s cards are in reverse order – the last card that they were dealt is on the top, and the first on the bottom.
How many times, including the first, must this process be repeated before the deck is back in its original order?
 

 

Input
There will be multiple test cases in the input. Each case will consist of a single line with two integers, n and k (1≤ n≤800, 1≤ k≤800). The input will end with a line with two 0s.
 

 

Output
For each test case in the input, print a single integer, indicating the number of deals required to return the deck to its original order. Output each integer on its own line, with no extra spaces, and no blank lines between answers. All possible inputs yield answers which will fit in a signed 64-bit integer.
 

 

Sample Input
1 3 10 3 52 4 0 0
 

 

Sample Output
1 4 13
 

思路:以10 3 为例:题意很好理解,
1》通过一次变换,数值变化情况是
1 2 3 4 5 6 7 8 9 10
10 7 4 1 8 5 2 9 6 3
通过一次变化,下标变化情况是
1 2 3 4 5 6 7 8 9 10
4 7 10 3 6 9 2 5 8 1
2》由此可以看出来:位置的变化有如下规律:
1->4->3->10->1;
2->7->2;
5->6->9->8->5;
可以知道这一串的变化周期是一样的,想变化到以前的位置次数也是相同的;
对于不同串的变换周期,要想最少nn次变化回来,那么要满足nn是他们的最小公倍数;
3》对于求下标和容易知道最后一个数n在的第几列,可以依次把该列的都求出来
那么根据这一列找到他右边的这里列最后的值即n+1-3,那么可以将此列的值全部求出来;
4》这是离散数学的知识点轮换;
1->4->3->10->1; 这称为一个轮换;
(1->4->3->10->1)*(2->7->2)*(5->6->9->8->5)
也就是3个轮换,每一个轮换中的元素无论执行多少次相同的置换都不会和其他轮换相交
所以结果就是 lcm(4,2,3)=4

代码如下:

#include<stdio.h>

#include<string.h>

int a[1000], vis[1000];

long long gcd(long long a, long long b) 

{ 

    return a ? gcd(b%a, a) : b; 

}

int main()

{

    int i, j, n, k, t;

    while(scanf("%d%d", &n, &k)!=EOF)

    {

         if(n==0&&k==0)

             break;

        t=0; 

        for(i=0; i<k&&i<n; i++)

            for(j=(n-i-1)/k*k+i; j>=0; j-=k)

                a[t++]=j;

         memset(vis, 0, sizeof(vis));

         long long ans, lcmnum=1; 

        for(i=0; i<n; i++)

        {

            int x=i;

            ans=0; 

            while(!vis[x])

            {

                ans++;

                vis[x]=1; 

                x=a[x];

            }

            if(ans) 

                lcmnum=lcmnum/gcd(lcmnum, ans)*ans;

        }

        printf("%I64d\n", lcmnum);

    }

}

 

你可能感兴趣的:(double)