HDU 4259 Double Dealing 8-25日网络赛1003题

 

第一次遇到20s的题,果断暴力,贡献多个TLE, 水题也不是完全水的,必须要适当的优化一下,学习了。

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define lld __int64

lld gcd(lld a, lld b)    //最大公约数 
{
    return a ? gcd(b%a, a) : b; 
}

int n, k;
int a[802];
bool vis[802];

int main()
{
    int i, j;
    while( ~scanf("%d%d", &n, &k) &&(n || k) )
    {
        int fx, fy, x, y;
        // 最后一位数字n-1的行列 ,数字从0开始 
        fx = (n - 1) / k + 1; 
        fy = (n - 1) % k + 1;
        for(i = 0; i < n; i++)
        {
            //数字i所在的行列 
            x = i / k + 1;
            y = i % k + 1;
            //行列右下角不一定有数字,矩阵有没填满的情况
            //计算出一次洗牌后i数字的位置,存在a[i]里面 
            if(y <= fy)
                a[i] = fx * y - x; 
            else 
                a[i] = (fx - 1) * y + fy - x;
        }
        memset(vis, 0, sizeof(bool) * n);
        int j;
        lld tmp, ans = 1;
        //对每个数找周期,并求这些周期的最小公倍数。 
        for(i = 0; i < n; i++)
        {
            j = i;
            tmp = 0;
            while(!vis[j])//出现以前出现过的数字,那么这个j的周期必然和 出现过的数字的周期是相同的,所以可以跳过 
            {
                vis[j] = 1;
                j = a[j];
                tmp++;
            }
            if(tmp)
            {
                if(ans == 1) ans = tmp;
                else ans = ans/gcd(tmp, ans) * tmp;
            }
        }
        printf("%I64d\n", ans);
    }
    return 0;
}

 

posted @ 2012-08-25 22:45  To be an ACMan  Views(254)  Comments(0)    收藏  举报