暑假集训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,是一个时代的终结。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值