備戰省賽組隊訓練賽(補題) D過分的謎題

                          問題 D: 過分的謎題時間限制: 1 Sec  內存限制: 128 MB

題目描述2060年是雲南中醫學院的百年校慶,於是學生會的同學們搞了一個連續猜謎活動:共有10個謎題,現在告訴所有人第一個謎題,每個謎題的答案就是下一個謎題的線索…成功破解最後一個謎題後,答案就是指向獎勵的線索
在所有同學們的努力下,全校同學們獲得了最後一個謎題,這個謎題有幾十張紙,上面全是密密麻麻的數字以及’.’
第一頁內容如下:
1,2,3,4,5,6
4,1,5,2,6,3
2,4,6,1,3,5
1,2,3,4,5,6
———31,2,3,4…32


———10有細心的同學發現,這是對一組1-2n的序列進行如下移動:每次將前n個數字取出,按順序依次插入到位於n+1,n+2…2n的數字後面,最後的數字表示多少次移動後會變回原來的序列
第二頁內容如下:
1,2,3,4…64


———?1,2,3,4…140


———?同學們發現,越往後翻,這個序列的長度就越長,前面十幾二十個數字的序列同學們還可以一步一步模擬做出來,但是到後來幾千甚至上萬的長度,就沒有辦法計算了,甚至中間一步做錯,就步步都錯。
這個謎題真是太過分了!但是獎勵就在眼前,只要計算出所有答案,所有答案就是指引同學們獲得獎勵的線索,那麼現在問題來了,同學們除了發現上面的n=最後那個數字/2之外,沒有辦法給你任何幫助,而作爲一個計算機科學與技術專業的大佬,你自然就成爲了同學們心目中拯救他們的英雄,所以你能不能寫一個程序,當你知道n是多少的時候,可以直接得出答案呢?
輸入多組測試數據.每組數據的第一行包含一個正整數n(1<= n<=10000).
輸出每組數據輸出一行整數表示最少需要經過幾次移動能變回原序列,若不能,則輸出"-1"
。。
。。
。。
。。
這個題比賽時沒有看到,當時因爲週二晚上有課時間直接減少一半,沒來得及細看,只是找了A 的比較多的題做的
剛開始第一個思路本想直接用數組維護,找到變化的規律,然後把每次的新的一列數,更新數組來維護,當有一個數變爲原來的一樣時,其他數肯定保證也回到剛開始的位置,但是代碼嗎很長,最後提交也 TLE 超時了,然後準備先打表,然後直接輸出,但是打表時需要每次都將 a[] 數組初始化爲 1 到 maxn ,時間複雜度非常高,最後也是沒跑出來。
然後想到只要有一個數成立其他也成立的化,就可以只看第一個數,當第一個數回到初始狀態時,結束,同時打表直接輸出。
對每列數的第 i 個 經過一次變化後所處的位置爲 (i2)%(n2+1) n爲即爲題目中的 n
這個時剛開始那個TLE思路的代碼,運行結果是對的:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
int gcd(ll a,ll b)
{
    if(!b)
        return a;
    else
        return gcd(b,a%b);
}
ll a[100010];
ll b[100010];
void fun()							//這是上述維護 a[] 數組的函數
{
    for(int i=1;i<maxn;i++)
        a[i]=i;
}
int main()
{
    ll n;
    while(~scanf("%lld",&n))
    {
        fun();
        for(int i=1;i<=n*2;i++)
        {
            b[(a[i]*2)%(2*n+1)]=a[i];
        }
          ll num=1;
        while(b[1]!=1)
        {
           	 for(int i=1;i<=2*n;i++)
            	{
                	a[i]=b[i];
            	}
            	for(int i=1;i<=2*n;i++)
                	b[(i*2)%(2*n+1)]=a[i];
          	num++;
        }
        printf("%lld\n",num);
    }
    return 0;
}

下面時只看第一個數的ac代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=1e4+7;
int gcd(ll a,ll b)
{
    if(!b)
        return a;
    else
        return gcd(b,a%b);
}
ll a[100010];
ll b[100010];
ll ans[100010];
int main()
{
    ll n;
    for(int j=1;j<=maxn;j++)
    {
        fun();
        ll flag=0;
        for(int i=1;i<=j*2;i++)					//這一步有點多餘,目的爲找到1變化一次之後的位置,其實可以從題目中直接看出來時 2 
        {
            b[(i*2)%(2*j+1)]=a[i];
            if(b[(i*2)%(2*j+1)]==1)
                flag=(i*2)%(2*j+1);
        }
        ans[j]=1;
        while(flag!=1)							//當再次爲 1 的時候,此時asn [ j ] 即爲答案;
        {
            flag=(flag*2)%(j*2+1);		
            ans[j]++;
        }
    }
    while(~scanf("%lld",&n))
    {
        printf("%lld\n",ans[n]);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章