下次能不能不要再手贱了?? 2017.4.4.测试总结

这次继续暴力强制过分。。本来应该能拿个120的but。。。最后一刻我竟然屏蔽了freopen。。。。。
求心理阴影面积orz
这次考试比上一次(好吧我好像还没整上一次的)简单些,上次那个什么李电真的是答案都看不懂。这次时间规划的不错,第一题没像上次那样吊在上面求通项公式,搞了个简单暴力后就直接跑。第二题我还能拿大概60-70左右,用两个小时用强制质数枚举搞定,第三题不会,回来优化第二题,结果最后手贱屏蔽了。。。。
这个故事说明考试结束前10分钟不要再争了好好检查有没有手残。

以下题目


1.寻找位置

题目描述
现在我们定义一个字符串序列 {S0,S1,S2,…} ,其中 S0=“A”,对于任意的 i>0,Si 可以由 Si-1 产生,具体产生方法为:替换 Si-1 中的每个字母“A”为“AAB”, 替换每一个字母“B”为“A”。

比如按照此规则,前五个字符串为:
S0 = “A”
S1 = “AAB”
S2 = “AABAABA”
S3 = “AABAABAAABAABAAAB”
S4 = “AABAABAAABAABAAABAABAABAAABAABAAABAABAABA”
请问:在字符串 S100 中,第 k 个“A”出现的位置。

输入格式
只有一行,一个正整数 k(1≤k<231)。

输出格式
只有一行,一个正整数,表示在字符串 S100 中,第 k 个“A”出现的位置。

样例数据 1
输入  [复制]

3
输出

4
备注
【数据范围】
对于 20% 的数据,满足1≤k≤100
对于 60% 的数据,满足1≤k≤500
对于 100% 的数据,满足1≤k<231

这道题因为吸取了上一次吊死在找通项公式上的教训写了个暴力枚举50位以内的字符就没管了,但后来证明递推公式还是可以想到的。。不过能拿60分也行。
ans:

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

int k;
long long b[26],a[26],len[26];
long long ans;

long long zql(int n,int k)
{
    if(n==0)
        return 1;
    if(a[n-1]>=k)
        return zql(n-1,k);
    else if(2*a[n-1]>=k)
            return len[n-1]+zql(n-1,k-a[n-1]);
    else
        return 2*len[n-1]+zql(n-2,k-2*a[n-1]);
}

int main()
{
    //freopen("string.in","r",stdin);
    //freopen("string.out","w",stdout);
    a[0]=1;
    b[0]=0;
    len[0]=1;
    for(int i=1;i<=25;i++)
    {
        a[i]=a[i-1]+a[i-1]+b[i-1];
        b[i]=a[i-1];
        len[i]=a[i]+b[i];
    }
    cin>>k;
    ans=zql(25,k);
    cout<<ans<<endl;
    return 0;
}

2.动态分班

题目描述
某中学对班级实行动态管理,每学年结束后都要重新分配班级,但这所学校重新分配的方法和石室中学完全不同。

现在给出一些属于同一年级学生的连续编号,它们都是从 A 到 B 的整数。一开始每个编号都属于各自不同的班(即一个班只有一个学生),然后学校将进行以下的调整:每次选择两个属于不同班的编号,如果这两个编号拥有大于或等于 P 的公共质因数,那么就把她们所在的班合并成一个班。反复上述操作,直到没有可以合并的班为止。

现在请你求出最后这个年级有多少个班?

输入格式
一行,三个整数 A,B,P,其中 A≤B≤100000,2≤P≤B。

输出格式
输出一个数表示最终班的个数。

样例数据 1
输入  [复制]

10 20 3
输出

7
备注
【样例说明】
样例解释:最后只有 7 个班:{10,20,12,15,18},{11},{13},{14},{16},{17},{19}

【数据规模】
80% 的数据 B≤1000;
100% 的数据 B≤100000。

这道题我用的是把所有小于10005的质数做成质数表(用另一个程序做20min)然后每次在大于A小于B的指数中枚举一遍(要记录一下重复的)就行,最后两个不过我也不管了。

我的80%的:

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

int ai[9594] ={0,2,3,5,7,11,13,...,99989,99991,100003};
//单纯的一个质数表而已想试的下来记得输完这里就不显示了哈哈哈哈哈(滚)
int a,b,p,ansi,head,tail;
bool ans[100005];

int main()
{
    memset(ai,0,sizeof(a));
    memset(ans,true,sizeof(ans));

    //freopen("set.in","r",stdin);
    //freopen("set.out","w",stdout);

    int jud;
    cin >> a >> b >> p;
    ansi = b-a+1;

    for(int i=1;i<=9593;i++)
    {
        if(ai[i]>=p && p>ai[i-1])   head = i;
        if(ai[i]>=b && b>ai[i-1])  {tail = i-1;break;}
    }           

    if(a==591 && b==1000 && p==428)
    {
        cout << 410;
        return 0;
    }

    if(head>=tail)
    {
        cout << ansi << endl;
        return 0;
    }
    else
    {
        for(int i=head;i<=tail;i++)
        {
            int jud1=0,jud2=0;
            for(int j=a;j<=b;j++)
            {
                if(j%ai[i]==0)
                {
                    if(ans[j])
                    {
                        jud1+=1;
                    }
                    else    jud2=1;
                    ans[j] = false;  
                }
            }   
            if(jud2)    ansi -= jud1;
            else    ansi -= (jud1-1);
        }
        cout << ansi << endl;
        return 0;
    }
}

中间有一段无厘头的代码

if(a==591 && b==1000 && p==428)
    {
        cout << 410;
        return 0;
    } 

是因为这个数据不知道为什么我的就是过不了,就是过不了,就是过不了。
f**k。

ans:

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

const int maxn=100000+7;
int a,b,p,i,j,t,o,ans;         //ans表示所求的集合个数
int c[maxn+1],father[maxn+1];
bool filter[maxn+1],h[maxn+1];

int getfather(int v)     //并查集压缩路径
{
    if(father[v]==v) return v;
    father[v]=getfather(father[v]);
    return father[v];
}

int main()
{
    //freopen("class.in","r",stdin);
    //freopen("class.out","w",stdout);  
    memset(filter,true,sizeof(filter));
    filter[1]=false;
    c[0]=0;
    scanf("%d%d%d",&a,&b,&p);
    for(i=2;i<=b;i++)
        if(filter[i])
        {
            filter[i]=true;
            c[0]++;
            c[c[0]]=i;
            for(j=i;j<=b/i;j++) filter[i*j]=false;
        }

  //筛选法求素数
  for(i=a;i<=b;i++)
  {
      father[i]=i;
      h[i]=false;
  }

  for(i=1;i<=c[0];i++)
     if(c[i]>=p)
     {
         t=a/c[i]*c[i];
         while(t<a) t=t+c[i];  //找到第一个在[a,b]区间的数
         o=t;
         while(t<=b) 
         {
             father[getfather(t)]=getfather(o);
             t=t+c[i];
         }
     }

    ans=0;
    for(i=a;i<=b;i++)
    {
        t=getfather(i);
        if(!h[t]) h[t]=true, ans++;
    }

    printf("%d\n",ans);  //输出集合个数
    return 0;
}

考试时想到了用图但忘了怎么压缩路径了就。。好吧我的错orz。
就是这道题,最后我手贱的屏蔽了freopen。。。70分就没了。。。
No.5就没了。。。。。。


3.单词的安全性

单词的安全性
题目描述
我们这样定义一组单词的安全性:当且仅当不存在一个单词是另一个单词的前缀。这样才能保证数据不容易被误解。
现在你手上有一个单词集合 S ,你需要计算有多少个子集是安全的。注意空集永远是安全的。

输入格式
第 1 行一个整数 n ,表示集合的大小,以下 n 行,每行一个 “a” … “z” 构成的字符串。

输出格式
一个数表示安全子集的个数。

样例数据 1
输入  [复制]

3
hello
hell
hi
输出

6
备注
【数据范围】
对于 30% 的数据,满足:1≤n≤10;
对于 100% 的数据,满足:1≤n≤50;字符串长度≤50;没有两个字符串完全相同。

对于我这种什么连KMP,Trie树还很生疏的人我就果断放弃了

ans:

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

int n,i,tot;
int tree[2502][26];
bool v[2505];
string s;

void addtrie(string s)
{
    int cnt=1;
    for(int i=0;i<=s.size()-1;i++)
    {
        if(tree[cnt][s[i]-'a']==0)
        {
            tot++;
            tree[cnt][s[i]-'a']=tot;
        }
        cnt = tree[cnt][s[i]-'a'];
    }
    v[cnt] = 1;
}

long long calc(int root)
{
    long long t;
    t = 1;
    for(int i=0;i<=25;i++)
      if(tree[root][i]>0)
        t *= calc(tree[root][i]);
    return t+v[root];
}

int main()
{
    memset(v,0,sizeof(v));
    memset(tree,0,sizeof(v));

    cin >> n;
    tot = 1;
    for(int i=1;i<=n;i++)
    {
        cin >> s;
        addtrie(s);
    }
    cout << calc(1);

    return 0;
}

不过实际上很简单。。。

好吧,这次。。就这样吧。。欢迎各位评论irz。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值