Asce‘s Summer Ranking No.11

15 篇文章 0 订阅
时间限制 3000 ms  内存限制 65536 KB

题目描述

喜欢焦叔叔的小妹妹实在是太多了,以至于焦叔叔不得不给她们编号1-N。焦叔叔对于编号为质数的小妹妹有种特别的好感,由于有好感的小妹妹数目太多,焦叔叔自己都数不清楚了,请你来帮忙数一下。

输入格式

多组数据,每行一个正整数N,N不大于1000000000。

数据组数小于15。

输出格式

每行一个数字,有好感的小妹妹数。

输入样例

5

输出样例

3

有技巧的打表,分成根号n块,先找到在哪块里,把之前块的素数和用打表结果弄出来,再爆搜块内有多少小于它的素数。。

(当时一直以为有意想不到的公式,还是太年轻。。)


-----------------------------------------------------------------------------

时间限制 10000 ms  内存限制 65536 KB

题目描述

田田被老师要求背诵一个字符串,田田刚刚背了一个子串,说他记性差他还不承认,背下这个子串后却忘了这个子串是从哪里开始的。
现在田田把这个字符串给你,并且让你告诉他至少一次背多长的子串才不可能产生歧义,即不存在另一个子串与它相等

输入格式

输入仅一行,即要求田田背诵的字符串
长度<=10^6

输出格式

输出一行,即不产生歧义串的最小串长

输入样例

abcdabcd

输出样例

5
最长重复子串(后缀树的)+1,10的6次可以,直接上模板

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#define maxn 1000010
 
using namespace std;
 
string s;
int t;
char inps[maxn];
 
void radix(int *str,int *a,int *b,int n,int m)
{
    static int count[maxn];
    memset(count,0,sizeof(count));
    for(int i=0;i<n;++i) ++count[str[a[i] ] ];
    for(int i=1;i<=m;++i) count[i]+=count[i-1];
    for(int i=n-1;i>=0;--i) b[--count[str[a[i] ] ] ]=a[i];
}
 
void suffix_array(int *str,int *sa,int n,int m)
{
    static int rank[maxn],a[maxn],b[maxn];
    for(int i=0;i<n;++i) rank[i]=i;
    radix(str,rank,sa,n,m);
 
    rank[sa[0] ]=0;
    for(int i=1;i<n;++i) rank[sa[i] ]=rank[sa[i-1] ]+(str[sa[i] ]!=str[sa[i-1] ]);
 
    for(int i=0;1<<i <n;++i)
    {
        for(int j=0;j<n;++j)
        {
            a[j]=rank[j]+1;
            b[j]=j+(1<<i)>=n?0:rank[j+(1<<i) ]+1;
            sa[j]=j;
        }
        radix(b,sa,rank,n,n);
        radix(a,rank,sa,n,n);
        rank[sa[0] ]=0;
        for(int j=1;j<n;++j)
        {
            rank[sa[j] ]=rank[sa[j-1] ]+(a[sa[j-1] ]!=a[sa[j] ] || b[sa[j-1] ]!=b[sa[j] ]);
        }
    }
}
int substr(string str)
{
    string rev;
    static int s[maxn],sa[maxn],rank[maxn],h[maxn];
    int n=str.length();
    copy(str.begin(),str.end(),s);
    suffix_array(s,sa,n,256);
 
    for(int i=0;i<n;i++) rank[sa[i]]=i;
 
    int k=0;
    int ans1=0,pos1=0;
    for(int i=0;i<n;++i)
    {
        k= k==0?0:k-1;
        while(rank[i]>0 && s[i+k]==s[sa[rank[i]-1]+k ]) ++k;
        h[rank[i] ]=k;
 
        if(h[rank[i] ]>ans1)
        {
            ans1=h[rank[i] ];
            pos1=i;
        }
    }
    return ans1;
}
int main()
{
        scanf("%s",inps);
        s.assign(inps);
        printf("%d\n",substr(s)+1);
    return 0;
}

---------------------------------------------------------------------------------

时间限制 1000 ms  内存限制 65536 KB

题目描述

在广茂的大森林里居住着一位可爱的小妹妹,以及一位怪叔叔。这天,怪叔叔让小妹妹为他做一锅蘑菇汤,可怜的小妹妹只好出门采集蘑菇。怪叔叔知道,森林里一共有n种不同的蘑菇,所以他提出了一个变态的要求,小妹妹必须为他做一锅包含所有n种蘑菇的汤。也就是说,小妹妹至少要采集齐所有的n种蘑菇。她想知道,平均要采多少朵蘑菇能满足怪叔叔的要求,注意,她每次所采的蘑菇是等概率的。

输入格式

多组case,case<=100。每组case一行一个数n,1<=n<=100。输入以EOF结束。

输出格式

每组case输出一行答案,保留六位小数。

输入样例

1
2

输出样例

1.000000
3.000000
概率题,最简单的想法,假设需要n种蘑菇,当前已踩到i种,则下次采有(n-i)/n的可能踩到不一样的,取个倒数,也就是采n/(n-i)次能踩到1种不一样的

把i从1到n的值加起来就好了~

(错位相减什么的推出来的,我表示高中那玩意儿就没怎么算对过,实在不敢用)

#include <iostream>
#include <cstdio>
 
using namespace std;
 
int n;
double ans;
 
int main()
{
    while(~scanf("%d",&n))
    {
        ans=0;
        for(int i=1;i<=n;i++) ans+=((double)n)/((double)i);
 
        printf("%.6lf\n",ans);
    }
    return 0;
}

-----------------------------------------------------

时间限制 1000 ms  内存限制 65536 KB

题目描述

焦级长特别喜欢设计电脑游戏,他刚刚给他的防御工事设计了一套激光炮防御系统,该系统有N座激光炮,每座可以发射足够束激光炮,但每次只能发射一束。发射时,需要T1秒才能射出,发射后需要T2分钟的冷却时间。每束激光的速度均为V(km/min),并且会沿距离最短的路径去打击目标,为简化问题,计算激光在空中的时间只需将激光炮到目标的水平距离(km)除以V(km/min)即可,单位为分钟。现在给出N座激光炮的坐标,M个敌人的坐标,T1,T2和V,求出至少多少分钟焦级长的防御工事能消灭所有敌人。

输入格式

输入为多组数据,第一行为五个正整数N,M,T1,T2,V,接下来M行每行两个整数代表敌人坐标,接下来N行每行两个整数代表激光炮坐标。
1<=N<=50,1<=M<=50,坐标绝对值不超过10000,T1,T2,V不超过2000。

输出格式

输出一个实数表示最少需要多少分钟才能消灭完所有敌人,四舍五入保留六位小数。

输入样例

3 3 30 20 1
0 0
0 50
50 0
50 50
0 1000
1000 0

输出样例

91.500000
二分匹配问题,总以为求最优的要用km算法是,丁神于是推荐了 poj 3343这个神题,明白了要先二分时间,再判断在时间k内的最大匹配,匈牙利一下,看是否等于敌人数

但是,如果炮比敌人少怎么办呢?菊苣教育我们,把炮拆点,打的每炮拆成一个点,共n*m个点,就好了~






-----------------------------------------------------------------

时间限制 1000 ms  内存限制 65536 KB

题目描述

小妹妹和叔叔来到了小明湖畔划船,到了湖中间的时候,叔叔突然手一抖就把桨掉到了水里。叔叔对小妹妹说:“怎么办呀我们没办法划船了,我们是不是就只能这样子一直两个人呆在湖中央了呢~?”。 机智的小妹妹想了一会儿,她说:“我发现,靠风来吹我们的船也是可以动的哟~你说风什么时候能把我们吹回码头?” 这下次可难倒叔叔了,请你帮助他解决这个问题好不让小妹妹失望。 叔叔的船现在在sx,sy位置,而码头在ex,ey位置。 我们假设风只向东(E)南(S)西(W)北(N)四个方向吹,且每吹一次风: 东风将船向x+1,y方向吹; 南风将船向x,y-1方向吹; 西风将船向x-1,y方向吹; 北风将船向x,y+1方向吹。 请问叔叔和小妹妹最早什么时间回到码头?注意,小妹妹的船是有锚的~她不希望船动的话叔叔就在第一时间把锚抛下去。

输入格式

输入包含多组数据。每组输入第一行包含五个整数,t,sx,sy,ex,ey,第二行包含t个字符,仅含'E','S','W','N'。

坐标绝对值小于1000000000。t<=100000。输入保证起点重、终点坐标不相同。

输出格式

输出一个t表示最早到达码头的时间,如果到达不了则输出-1。

输入样例

5 0 0 1 1
SESNW

输出样例

4
模拟就可以,如果顺风,就动,如果逆风就扔锚停住

(开始没看懂题以为那个(x,y+1)只是代表方向向量,wa了后换成了每次移动一格的理解方式,就过了。。)

#include <iostream>
#include <cstdio>
#include <cmath>
#define maxt 100005
 
using namespace std;
 
char input[maxt];
int t,sx,sy,ex,ey,ans;
 
int counting(char dir1,char dir2)
{
    int flag1=0,flag2=0;
    int i;
    for(i=0;i<t;i++)
    {
        if(input[i]==dir1) flag1++;
        if(input[i]==dir2) flag2++;
        if(flag1==abs(sy-ey) && flag2==abs(sx-ex)) break;
    }
    if(i==t) return -1;
    else return i+1;
}
 
 
 
int main()
{
    while(~scanf("%d%d%d%d%d",&t,&sx,&sy,&ex,&ey))
    {
        scanf("%s",input);
        if(ex>sx)
        {
            if(ey>sy)
            {
                ans=counting('N','E');
            }
            else
            {
                if(ey==sy)
                {
                    ans=counting('0','E');
                }
                else
                {
                    ans=counting('S','E');
                }
            }
        }
        else
        {
            if(ex==sx)
            {
                if(ey>sy)
            {
                ans=counting('N','0');
            }
            else
            {
                if(ey==sy)
                {
                    printf("0\n");
                    continue;
                }
                else
                {
                    ans=counting('S','0');
                }
            }
            }
            else
            {
                if(ey>sy)
            {
                ans=counting('N','W');
            }
            else
            {
                if(ey==sy)
                {
                    ans=counting('0','W');
                }
                else
                {
                    ans=counting('S','W');
                }
            }
            }
        }
 
        printf("%d\n",ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值