zoukankan      html  css  js  c++  java
  • 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 kth to player k, the k+1st 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);
        }
    }
  • 相关阅读:
    套用JQuery EasyUI列表显示数据、分页、查询
    Linux 进程间通信 信号
    Linux socket编程
    Linux字符设备驱动注册流程
    Linux杂项设备与字符设备
    Linux并发控制解决竞态的一种操作>原子操作
    Linux 进程间通信 管道通信
    Linux串口编程
    博客开通啦!
    实现Windows Phone 8多媒体:视频
  • 原文地址:https://www.cnblogs.com/Hilda/p/2656864.html
Copyright © 2011-2022 走看看