暑假集訓test14

我會告訴你test13被我吃了嗎?
當然不會。
哦其實還多吃了一道題。。。。。

1.Fancy Signal Translate

FST是一名可憐的 OIer,他很強,但是經常 fst,所以 rating 一直低迷。

但是重點在於,他真的很強!他發明了一種奇特的加密方式,這種加密方式只有OIer
才能破解。

這種加密方式是這樣的:對於一個 01 串,他會構造另一個 01 串,使得原串是在新串中沒有出現過的最短的串。

現在 FST 已經加密好了一個串,但是他的加密方式有些 BUG ,導致沒出現過的最短的串不止一個,他感覺非常懊惱,所以他希望計算出沒出現過的最短的串的長度。

輸入格式

一行,一個 01 串。

輸出格式

一行,一個正整數,表示沒有出現過的最短串的長度。

樣例數據

輸入
100010110011101

輸出
4

備註

【數據範圍】
測試點 1、2、3 的串長度≤10;
測試點 3、4、5 的串長度≤100;
測試點 6、7、8、9、10 的串長度≤10^5;

唔,根據某。。。證明答案很小,所以直接枚舉答案長度,對於某種長度,掃描字符串,2^ans存儲每種串有沒有出現過。可以加上Hash的優化。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

int n,m,l,r,mid,ans;
char s[200000];
bool f[200000];

inline bool zql(int x)
{
    int j;
    long long num=0,t=0;
    memset(f,false,sizeof(f));
    for(j=n;j>=n-x+1;j--)
        if(s[j]=='1')
            num+=1<<(n-j);
    if(f[num]==false)
    {
        f[num]=true;
        t++;
    }                               //是否長度爲x的串都存在。
    for(;j>=1;j--)
    {
        num=num>>1;
        if(s[j]=='1')
            num+=1<<(x-1);
        if(f[num]==false)
            t++;
        f[num]=true;
    }
    if(t==(1<<x))
        return true;
    else
        return false;
}

int main()
{
    //freopen("fst.in","r",stdin);
    //freopen("fst.out","w",stdout);
    scanf("%s",s+1);
    n=strlen(s+1);
    l=0,r=17;
    while(l+1<r)
    {
        mid=(l+r)/2;
        if(zql(mid))
            l=mid;
        else            //這裏二分,若是長度爲mid的串都出現,則在上界裏找。
            r=mid;
    }
    cout<<l+1<<endl;
    return 0;
}

2.Factorial Surplus Tail

FST 作爲 OIer ,經常會遇到和階乘有關的問題,但是一個數的階乘末尾總是會有很多 0 ,FST 認爲這很不美觀,但是 FST 覺得如果 0 的個數是偶數的話,還是可以接受的。

所以就有這樣一個問題,FST 想知道 0!,1!,2!… … (n-1)!,n! 中有多少數的末尾 0 個數是偶數。(注意0!是1,0算偶數)

輸入格式

讀入有若干行,每行一個正整數 n ,最後一行是一個 -1 。

輸出格式

對於每個 n 輸出一行,爲 0!,1!,2!… … (n-1)! ,n! 中末尾 0 個數是偶數的個數。

樣例數據

輸入
2
3
10
-1

輸出
3
4
6

備註

【數據範圍】
測試點 1、2:n≤10;數據組數=1;
測試點 3、4:n≤10000;數據組數=10;
測試點 5、6、7、8:n≤10^9;數據組數=10^5;
測試點 9、10:n≤10^18;數據組數=10^5;

強行復制題解,如下。
題解:
首先我們發現一個數如果不是5的倍數,那麼他的答案一定是和上一個數一樣的,因此我們首先把n的多餘部分處理掉,使數的個數是5的倍數,再把n除以5,(最後記得把答案除以5))

然後我們就只需要處理0×5,1×5,2×5,…n×5這個序列,我們發現一個數k×5,如果k不是5的倍數,那麼他的答案和(k-1)×5是相反的,因此我們還是先把n的多餘部分處理掉,使數的個數是5的倍數,然後看如果5個5個一組一共有多少組,每組中k不是5的倍數的數一定會貢獻2的答案,因此我們把答案加上組數×2,然後再把n除以5

現在我們只需要處理0×25,1×25,2×25…n×25這個序列,我們發現k×25和k的答案是一樣的,因此這個序列和0,1,2…n的答案是一樣的,因此我們遞歸的處理就行了,此時n已經是之前的1/25了

現在我們來證明k*25和k的答案是一樣的:
一個數p的答案顯然就只和[p/5]+[p/25]+[p/125]+…的奇偶性有關,而25*k只比k多了兩項就是[5*k]+[k]=6*k,這是個偶數,不影響奇偶性。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
using namespace std;

long long ans,n=0,zql,tot,i,j;
long long f[105],g[105][2];

int main()
{
    //freopen("fstagain.in","r",stdin);
    //freopen("fstagain.out","w",stdout);

    f[0]=1;
    for(int i=1;i<=25;i++)
        f[i]=f[i-1]*5;
    g[0][0]=1;
    for(int i=1;i<=25;i++)
        if(i%2==1)
            g[i][0]=g[i-1][0]*5,g[i][1]=g[i-1][1]*5;
    else
    {
        g[i][0]=g[i-1][0]*3+g[i-1][1]*2;
        g[i][1]=g[i-1][1]*3+g[i-1][0]*2;
    }
    while(n>=0)
    {
        cin>>n;
        if(n<0)
            break;
            ans=0,zql=0;
        for(int i=25;i>=0;i--)
        {
            for(int j=1;j<=n/f[i];j++)
            {
                ans+=g[i][zql];
                if(i&1)
                    zql^=1;
            }
            n%=f[i];
        }
        cout<<ans+g[0][zql]<<endl;
    }
    return 0;
}

嗯對就這樣。
安。

來自2017.8.23.

——我認爲return 0,是一個時代的終結。

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