Double Dealing----HDU4259----找规律

来源:互联网 发布:高薪职业知乎 编辑:程序博客网 时间:2024/06/10 17:54

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4259

/*Author:Bob Lee2012.8.27===================================首先是题目意思的理解问题有n张牌,然后一次给k个人,多的话就循环着给然后依次将每个人手中的牌收回来,第一个的放在最上面,并且是倒着的例如1手中的是1,4,7,10那么收回去放着的时候就是10,7,4,1一次往后放,然后再发,再收回来,问你要多少次的循环才能恢复到初始的情况这个就是题意。以样例10,3来说第一次之后为10,7,4,1,8,5,2,9,6,3第二次之后为3,2,1,10,9,8,7,6,5,4第三次之后为4,7,10,3,6,9,2,5,8,1第四次之后为1,2,3,4,5,6,7,8,9,10我们可以发现一个规律,1它的位置变化是1-4-3-10-1而4的位置变化为4-3-10-1-43的位置变化为3-10-1-4-310的位置变化为10-1-4-3-10不难得出结论这一个循环上的数字的位置变化是一样的,也就是他们要回到自己的初始位置的步数是一样的那么我们的任务就变成来找出每个这种链的步数,然后求出他们的最小公倍数,这样就得到了结果这个例子中其它的就是2-7-2和5-6-9-8-5这个规律我们可以在一次模拟之后就知道了,那么我们首先要做的就是模拟一次,然后通过递推a[data[i]] = i的到我们要得循环链因为1下一个是4,4后面是10,10后面是3,这样是不是就出来了?还有一个我们可以发现当n<=k的时候,每个人手中是只有一张牌的,那么收回的时候根本就不会影响到顺序,也就是只要1次就够了,这个就可以加进去优化一下*/#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<algorithm>using namespace std;#define MAXN 1000long long a[MAXN];long long data[MAXN];struct player{    int count;    int num[MAXN];}p[MAXN];bool visit[MAXN];int n,k;void init(){    for(int i=1;i<=n;i++)    {        p[i].count = 0;        visit[i] = false;        data[i] = i;    }}void give()//模拟给牌的过程{    int i;    for(i=1;i<=n;i++)    {        int t = i%k;        if(t==0)            p[k].num[++p[k].count] = data[i];        else            p[t].num[++p[t].count] = data[i];    }}void back()//模拟收牌的过程{    int i,j;    int q = 1;    for(i=1;i<=k;i++)    {        for(j = p[i].count ; j>=1 ;j--)        {            data[q++] = p[i].num[j];        }    }    //由于已经模拟来一次过程,我们就可以找出规律了    for(i=1;i<=n;i++)    {        a[data[i]] = i;    }}long long gcd(long long a,long long b)//求最小公约数{    return a ? gcd(b%a, a) : b;}int main(){    while(scanf("%d%d",&n,&k) && n+k)    {        if(n<=k)//那个优化的过程        {            cout<<1<<endl;            continue;        }        init();        give();        back();        long long ans = 1;        for(int i=1;i<=n;i++)        {            if(visit[i])//如果这个循环节已经访问过来,则跳过                continue;            long long cnt = 0;            int key = i;            while(!visit[key]){                visit[key] = true;                cnt++;                key = a[key];            }            //求出它们的最小公倍数            ans = ans/gcd(ans,cnt)*cnt;        }        cout<<ans<<endl;    }    return 0;}



原创粉丝点击