Problem A
度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到:
H(s)=\prod_{i=1}^{i\leq len(s)}(S_{i}-28)\ (mod\ 9973)H(s)=∏i=1i≤len(s)(Si−28) (mod 9973)
S_{i}Si代表 S[i] 字符的 ASCII 码。
请帮助度熊计算大字符串中任意一段的哈希值是多少。
多组测试数据,每组测试数据第一行是一个正整数NN,代表询问的次数,第二行一个字符串,代表题目中的大字符串,接下来NN行,每行包含两个正整数aa和bb,代表询问的起始位置以及终止位置。
1\leq N\leq 1,0001≤N≤1,000
1\leq len(string)\leq 100,0001≤len(string)≤100,000
1\leq a,b\leq len(string)1≤a,b≤len(string)
对于每一个询问,输出一个整数值,代表大字符串从 aa 位到 bb 位的子串的哈希值。
2 ACMlove2015 1 11 8 10 1 testMessage 1 1
6891 924088
解:思路很简单,就是把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: 728Submissions: 2903Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/65536 K (Java/Others)解:推了一下,就是个菲薄垃圾数列,dp[i]=dp[i-1]+dp[i-2].这里我用的是JAVA过的,比较简单。不过,坑点就是在于当n=0时,输出换行。Problem Description度熊面前有一个全是由1构成的字符串,被称为全1序列。你可以合并任意相邻的两个1,从而形成一个新的序列。对于给定的一个全1序列,请计算根据以上方法,可以构成多少种不同的序列。
Input这里包括多组测试数据,每组测试数据包含一个正整数NN,代表全1序列的长度。
1\leq N \leq 2001≤N≤200
Output对于每组测试数据,输出一个整数,代表由题目中所给定的全1序列所能形成的新序列的数量。
Sample Input1 3 5Sample Output1 3 8Hint如果序列是:(111)。可以构造出如下三个新序列:(111), (21), (12)。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: 860Submissions: 2290Time 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 Input5 ACM MAC BBA ACM BABSample Output0 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; }