Test 8 for NOIP- Result for Day1

头大

这个暑假完就要去搞NOIP了。。。

暑假55天也就20次测试。。。为防万一我还是每次测试玩都写个总结。。


。。放假两周回来发现被骂多了之后变得和智障一样。。day1 20分day2 140分才好一点。。马上就开学了。。虽然说被免了作业但是很久没练题了。。开学考试怕是要完(成外又不考试)。。语文更是没动。。一天到晚大半天时间在机房里后晚上就彻底颓废了。。

Day1 (20/300)

T1 FST(Fancy Signal Translate)(40/100)

题目描述
FST是一名可怜的 OIer,他很强,但是经常 fst,所以 rating 一直低迷。

但是重点在于,他真的很强!他发明了一种奇特的加密方式,这种加密方式只有OIer
才能破解。

这种加密方式是这样的:对于一个 01 串,他会构造另一个 01 串,使得原串是在新串中没有出现过的最短的串。

现在 FST 已经加密好了一个串,但是他的加密方式有些 BUG ,导致没出现过的最短的串不止一个,他感觉非常懊恼,所以他希望计算出没出现过的最短的串的长度。

输入格式
一行,一个 01 串。

输出格式
一行,一个正整数,表示没有出现过的最短串的长度。

样例数据 1
输入  [复制]

100010110011101
输出

4
备注
【数据范围】
测试点 1、2、3 的串长度≤10;
测试点 3、4、5 的串长度≤100;
测试点 6、7、8、9、10 的串长度≤10^5;

MY.CPP

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

int n,t=1,a[100005],b[100005];
char c[100005];
bool hash1[100005],hash2[100005];

void check(int k,int j)
{
    cout << "c: ";
    for(int i=0;i<n;i++)cout << c[i];
    cout << endl;
    cout << "b: ";
    for(int i=1;i<=k;i++)cout << " ";
    for(int i=1;i<=j-k;i++)cout << b[i];
    cout << endl << endl;
}

int main()
{
    //freopen("fst.in","r",stdin);
    //freopen("fst.out","w",stdout);
    gets(c);    
    n = strlen(c);
    while(pow(2,t)<=n)t++; 
    while(t--)
    {
        int flag=0,jud1=0,jud2=0,x0;
        memset(a,0,sizeof(a));
        memset(hash1,0,sizeof(hash1));
        memset(hash2,0,sizeof(hash2));
        int i,j;
        for(i=0;i<=n-t;i++)
        {
          jud1=0;   jud2=0;
          memset(b,0,sizeof(b));    
          for(j=i;j<=i+t-1;j++)
          {
            b[j-i+1] += c[j]-'0';
            if(c[j]-'0'==0) x0=1;
            else
            {
                jud1 += pow(2,j-i);jud1%=100005;
                jud2 += pow(5,j-i);jud2%=100005;    
            }       
          }    
          if(!hash1[jud1]&&!hash2[jud2])
          {
            hash1[jud1] = true;
            hash2[jud2] = true;
            for(int i=1;i<=t;i++)   a[i] += b[i];
          }
          //check(i,j);
        }         
        if(t==1) 
        {
            if(a[1]=1&&x0) flag=0;
            else    flag=1;
        }
        else 
        for(int i=1;i<=t;i++)
          if(a[i]<pow(2,t-1))
            {flag=1;break;}

        if(!flag)break;
    }
    cout << t+1 << endl;
}

搞了半天又是哈希又是统计才得了40分。。一开始看题解还要用二分。。
结果最短的题解直接哈希搞定,直接记录每个18位以下的二进制数。。(正好不超int)

STD.CPP

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

char s[100003];
bool vis[300000][20];
int i,j,sum,lenm;

int main(){
    scanf("%s",s+1);
    lenm=strlen(s+1);
    for(i=1;i<=lenm;i++)
    {
        sum=0;
        for(j=0;j<=min(17,(lenm-i));j++)
            sum=(sum<<1)+s[i+j]-'0',vis[sum][j+1]=true;
    }
    for(i=1;i<=18;i++)
        for(j=0;j<=((1<<i)-1);j++)
            if(!vis[j][i]){cout<<i<<endl;exit(0);}
}

。。这心机答案。。我以为可能有100位以上的二进制数就没敢直接用哈希。。WTF。。

T2 FST(Factorial Surplus Tail)(0/100)

题目描述
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 个数是偶数的个数。

样例数据 1
输入  [复制]

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整除的规律。。这题GG我服。

STD.CPP

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
long long f[105],ans,num[105][2],n,tmp,tot,i,j;
int main()
{  
     f[0]=1; 
     for (i=1;i<=25;i++) f[i]=f[i-1]*5;
     num[0][0]=1;
     for (i=1;i<=25;i++) 
         if (i%2==1)num[i][0]=num[i-1][0]*5,num[i][1]=num[i-1][1]*5;
         else 
             num[i][0]=num[i-1][0]*3+num[i-1][1]*2,
             num[i][1]=num[i-1][1]*3+num[i-1][0]*2;
    cin >> n;
    while (n!=-1)
   { ans=0; 
     tmp=0;
     for (i=25;i>=0;i--)
     {for (j=1;j<=n/f[i];j++)
       {
        ans+=num[i][tmp];
        if (i%2==1) tmp^=1;
       }
       n%=f[i];
     }
     cout << ans+num[0][tmp] << endl; 
     cin >> n;
   }
}

注意RMQ与LCA之间的联系,很可能会考

T3 FST(Fantasy Strange Tree)(30/100)

题目描述
FST 的脑洞非常大,经常幻想出一些奇怪的东西。

某一天,FST 幻想出了一棵没有边际的二叉树,脑补着在那棵二叉树上行走的场景。

FST 一开始在二叉树的根,然后 FST 写下了一个由 ‘L’‘R’ 两种种字符构成的串,他称这个串为初始串,按照这个串的顺序,碰到一个 ‘L’ 就移动到左儿子,碰到一个 ‘R’ 就移动到右儿子。FST 最后的位置就是他的起点。

然后 FST 有写下一个串,他称这个串为操作串,由 ‘U’‘L’‘R’ 三种字符构成,‘U’ 表示移动到当前点的父亲(特殊地,我们定义根节点的父亲为根自己), ‘L’ ‘R’ 同上。

但是 FST 觉得直接按照操作串一步一步走十分无聊,所以 FST 会跳过一些操作(心情不好的时候也可能跳过所有操作,或不跳过),现在 FST 想知道他会走到多少种可能的终点。

由于答案可能很大,所以只需输出答案 mod(10^9+7) 的值。

输入格式
第一行一个由‘L’‘R’两种字符构成的串。
第二行一个由‘U’‘L’‘R’三种字符构成的串。

输出格式
输出一行,为答案 mod(10^9+7)。

样例数据 1
输入  [复制]

LL
RU
输出

3
备注
【样例说明】
FST 可以操作的串为 ” ‘R’ ‘U’ ‘RU’。
但是串 ‘RU’ 的效果和串 ” 是一样的,所以只能走到 3 个节点。

如果最后没有智障的输出ans+1我就能拿到30分。。

MY.CPP

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

int n,dep,ans=0;
char s1[100005],s2[100005];
bool hash[10500050];
int loc=1;

void dfs(int step,int pos)
{
    ans += 1; hash[pos]=true;
    if(step>n)return;
    for(int i=step+1;i<n;i++)
    {
        if(s2[i]=='L')
          if(!hash[pos*2])
            dfs(i,pos*2);
        if(s2[i]=='R')
          if(!hash[pos*2+1])
            dfs(i,pos*2+1);
        if(s2[i]=='U')
          if(!hash[pos/2]&&pos/2)
            dfs(i,pos/2);
    }
}

int main()
{
    gets(s1);   dep = strlen(s1);
    for(int i=0;i<dep;i++)
    {
        if(s1[i]=='L') loc = 2*loc;
        if(s1[i]=='R') loc = 2*loc+1;
    }
    gets(s2);   n = strlen(s2);
    dfs(-1,loc);
    cout << ans;
}

当然这种暴力要是二叉树的深度稍微大一点就会GG
题解的Dp虽然复杂但不是很难想。。

STD.CPP

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
const int kkk = 100010;
using namespace std;
int f[kkk][5],i,j,n,m,mod=1000000007;
char s1[kkk],s2[kkk];
bool st[kkk][3];
int main()
{  
    scanf("%s",s1+1);
    n=strlen(s1+1);
    scanf("%s",s2+1);
    m=strlen(s2+1);
    for (i=1;i<=n;i++)
        if (s1[i]=='L') st[i][2]=true;//<-记录第一次访问的路径
        else st[i][1]=true;
            f[0][1]=1;//<-记录答案
            f[0][2]=1;//<-记录还剩余多少没走过的右子树(子树的根是一个已经经过过的点的右儿子)
            f[0][3]=1;//<-记录还剩余多少没走过的左子树(子树的根是一个已经经过过的点的左儿子)
            f[0][4]=n;//<-记录是否到了整棵树的根
    for (i=1;i<=m;i++)
    { if (s2[i]=='L')
       {f[i][1]=(f[i-1][1]+f[i-1][2])%mod;
        f[i][2]=f[i-1][2];
        f[i][3]=(f[i-1][2]+f[i-1][3])%mod;
        f[i][4]=f[i-1][4];
       }
      if (s2[i]=='R')
       {f[i][1]=(f[i-1][1]+f[i-1][3])%mod;
        f[i][2]=(f[i-1][2]+f[i-1][3])%mod;
        f[i][3]=f[i-1][3];
        f[i][4]=f[i-1][4];
       } 
      if (s2[i]=='U')
       { 
         if (f[i-1][4]>=1){
            f[i][1]=(f[i-1][1]+1)%mod;
            f[i][4]=f[i-1][4]-1;
            if (st[f[i-1][4]][1]==1) f[i][2]=f[i-1][2]+1,f[i][3]=f[i-1][3];
            if (st[f[i-1][4]][1]==0) f[i][3]=f[i-1][3]+1,f[i][2]=f[i-1][2]; 
         }
         if (f[i-1][4]==0){
            f[i][1]=f[i-1][1];
            f[i][2]=f[i-1][2];
            f[i][3]=f[i-1][3];
            f[i][4]=f[i-1][4];
         }
       }
    }
    cout << f[m][1] << endl;
}

代码。。只是有点绕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值