2016"百度之星" - 资格赛(Astar Round1)

116 篇文章 0 订阅
69 篇文章 0 订阅

Problem A

 
 Accepts: 599
 
 Submissions: 5110
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到:

H(s)=\prod_{i=1}^{i\leq len(s)}(S_{i}-28)\ (mod\ 9973)H(s)=i=1ilen(s)(Si28) (mod 9973)

S_{i}Si代表 S[i] 字符的 ASCII 码。

请帮助度熊计算大字符串中任意一段的哈希值是多少。

Input

多组测试数据,每组测试数据第一行是一个正整数NN,代表询问的次数,第二行一个字符串,代表题目中的大字符串,接下来NN行,每行包含两个正整数aabb,代表询问的起始位置以及终止位置。

1\leq N\leq 1,0001N1,000

1\leq len(string)\leq 100,0001len(string)100,000

1\leq a,b\leq len(string)1a,blen(string)

Output

对于每一个询问,输出一个整数值,代表大字符串从 aa 位到 bb 位的子串的哈希值。

Sample Input
2
ACMlove2015
1 11
8 10
1
testMessage
1 1
Sample Output
6891
9240

88

解:思路很简单,就是把1-n的乘积放在一个dp数组里面,最后ans=dp[r]/dp[l-1] %mod.当然乘法逆元肯定是要用到的。

#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const LL maxm=1e5+10;
const LL mod=9973;
string s;
LL dp[maxm];
LL quickmod(LL a,LL b)
{
    LL sum=1;
    while(b)
    {
        if(b&1)
            sum=(sum*a)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return sum;
}
int main()
{
    LL n;
    while(scanf("%I64d",&n)!=EOF)
    {
       cin>>s;
        dp[0]=1;
        for(LL i=1; i<=s.length(); i++)
        {
            dp[i]=(dp[i-1]*(s[i-1]-28))%mod;
        }
       LL l,r;
        for(LL i=0; i<n; i++)
        {
            scanf("%I64d%I64d",&l,&r);
            if(l>r)
            {
                swap(l,r);
            }
            printf("%I64d\n",(dp[r]*(quickmod(dp[l-1],mod-2)%mod))%mod);
        }
    }
    return 0;
}

Problem B

 
 Accepts: 728
 
 Submissions: 2903
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

度熊面前有一个全是由1构成的字符串,被称为全1序列。你可以合并任意相邻的两个1,从而形成一个新的序列。对于给定的一个全1序列,请计算根据以上方法,可以构成多少种不同的序列。

Input

这里包括多组测试数据,每组测试数据包含一个正整数NN,代表全1序列的长度。

1\leq N \leq 2001N200

Output

对于每组测试数据,输出一个整数,代表由题目中所给定的全1序列所能形成的新序列的数量。

Sample Input
1
3
5
Sample Output
1
3
8


        
        
Hint
如果序列是:(111)。可以构造出如下三个新序列:(111), (21), (12)。
解:推了一下,就是个菲薄垃圾数列,dp[i]=dp[i-1]+dp[i-2].这里我用的是JAVA过的,比较简单。不过,坑点就是在于当n=0时,输出换行。
import java.util.Scanner;
import java.math.BigInteger;
public class Main {
    public static BigInteger[]dp=new BigInteger[205];
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner cin=new Scanner(System.in);
        //int n=cin.nextInt();
        Init();
        while(cin.hasNext())
        {
            int n=cin.nextInt();
            if(n>=1&&n<=200)
            {
                System.out.print(dp[n]);
            }
            System.out.println();
        }
        
        
    }
    public static void Init()
    {
        dp[1]=new BigInteger("1");
        dp[2]=new BigInteger("2");
        for(int i=3;i<=201;i++)
        {
            dp[i]=dp[i-1].add(dp[i-2]);
        }
    }

}

Problem D

 
 Accepts: 860
 
 Submissions: 2290
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

度熊所居住的 D 国,是一个完全尊重人权的国度。以至于这个国家的所有人命名自己的名字都非常奇怪。一个人的名字由若干个字符组成,同样的,这些字符的全排列的结果中的每一个字符串,也都是这个人的名字。例如,如果一个人名字是 ACM,那么 AMC, CAM, MAC, MCA, 等也都是这个人的名字。在这个国家中,没有两个名字相同的人。

度熊想统计这个国家的人口数量,请帮助度熊设计一个程序,用来统计每一个人在之前被统计过多少次。

Input

这里包括一组测试数据,第一行包含一个正整数NN,接下来的NN 行代表了 NN 个名字。NN 不会超过1,000,0041,000,004,他们的名字不会超过40位.

Output

对于每输入的一个人名,输出一个整数,代表这个人之前被统计了多少次。

Sample Input
5
ACM
MAC
BBA
ACM
BAB
Sample Output
0
1
0
2
1
解:大水题一道,排序一下,map一下,就完了
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<string>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
#define LL __int64
const LL maxm=1e5+10;
const LL mod=9973;
char s[maxm];
map<string,int>q;
int dp[maxm];
void Init()//素数线性筛
{
    int vis[maxm];
    int isprime[maxm];
    int prime[maxm];
    int cnt=0;
    memset(vis,0,sizeof(vis));
    memset(isprime,0,sizeof(isprime));
    memset(prime,0,sizeof(prime));
    for(int i=2; i<=maxm; i++)
    {
        if(!vis[i])
        {
            prime[cnt++]=i;
            vis[i]=1;
        }
        for(int j=0; j<cnt&&i*prime[j]<maxm; j++)
        {
            vis[i*prime[j]]=1;
        }
    }
    for(int i=0; i<cnt; i++)
    {
        isprime[prime[i]]=1;
    }
}
int POW(int n,int k)//n的k次方
{
    int sum=1;
    for(int i=1; i<=k; i++)
    {
        sum*=n;
    }
    return sum;
}
int quickmod(int a,int b,int mod)//快速
{
    int ans=1;
    a=a%mod;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    q.clear();
    for(int i=0; i<n; i++)
    {
        scanf("%s",s);
        int len=strlen(s);
        sort(s,s+len);
        printf("%d\n",q[s]++);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值