求字典序在 s1 和 s2 之间的,长度在 len1 到 len2 的字符串的个数,结果 mod 1000007。
数据范围:
,
注意:本题有多组输入
import java.util.Scanner;
/**
* 例如ab ce 1 2
* 过程分为以下几个阶段:
* 第一阶段:i=min=1;b c,sum=2;除开首字母(剩下只有i-1=0个字母)
* 第二阶段:i=max=2;ac ... az ,ba ... bz ,ca ,cb;sum = 2+26*2=54;
* 第三阶段:i=max=2;c d e(除开首字母(剩下只有i-1=1个字母),
判断大于b小于等于e的字符串个数);sum = 54+3=57;
* 第四阶段:减去等于ce这个不满足的条件。sum = 57-1 = 56;
* 注意:仅最后一个小于等于e这个条件需要减去,
例如abc bbc 1 3 ,i=2时,ac ... az,ba,bb这里这个bb不需要排除,因为bb<bbc
*
*/
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while (scan.hasNext()) {
String s = scan.nextLine();
String[] array = s.split(" ");
int min = Integer.parseInt(array[2]);
int max = Integer.parseInt(array[3]);
char[] ar = array[0].toCharArray();
char[] br = array[1].toCharArray();
long sum = 0;
for (int i = min; i <= max; i++) {
char a=ar[0];
char b=br[0];
sum += (long)Math.pow(26,i-1)*(b-a);
long suma = 0;
long sumb = 0;
for (int j = 1; j < ar.length; j++)// 找到比ar剩余字符串小的字符串个数
{
suma = suma + (ar[j] - 'a') * (long) Math.pow(26, i- 1 - j);
}
for (int j = 1; j < br.length; j++)// 找到比br剩余字符串小的字符串个数
{
sumb = sumb + (br[j] - 'a') * (long) Math.pow(26, i - 1 - j);
}
sum = sum + sumb-suma;
}
sum--;
System.out.println(sum % 1000007);
}
}
}
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
using namespace std;
const int mod = 1000007;
int dp1[100010], dp2[100010];
char s1[110], s2[110];
int l1, l2;
int main() {
while(scanf("%s %s %d %d", s1, s2, &l1, &l2) != EOF) {
memset(dp1, false, sizeof(dp1));
memset(dp2, false, sizeof(dp2));
int n1 = strlen(s1);
int n2 = strlen(s2);
dp1[0] = 1;
dp2[0] = 1;
for(int i = 1; i <= l2; ++i) {
if(i < n1) {
dp1[i] = ((dp1[i-1]-1)*26 + (s1[i-1]-'a'+1)) % mod;
} else if(i == n1) {
dp1[i] = ((dp1[i-1]-1)*26 + (s1[i-1]-'a')) % mod;
} else {
dp1[i] = dp1[i-1]*26%mod;
}
if(i < n2) {
dp2[i] = ((dp2[i-1]-1)*26 + (s2[i-1]-'a'+1)) % mod;
} else if(i == n2) {
dp2[i] = ((dp2[i-1]-1)*26 + (s2[i-1]-'a')) % mod;
} else {
dp2[i] = dp2[i-1]*26%mod;
}
}
int sum1 = 0, sum2 = 0, ans;
for(int i = l1; i <= l2; ++i) {
sum1 += dp1[i];
sum1 %= mod;
sum2 += dp2[i];
sum2 %= mod;
}
ans = sum2 - sum1;
if(l2 >= n1) ans--;
printf("%d\n", (ans%mod+mod)%mod);
}
return 0;
}
计算比字符串s1大的len1~len2字符串个数 - 比s2大的len1~len2字符串个数即为在两个字符串中的个数。
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <math.h>
int calsubstring(int len1,int len2){
int rt = 0;
rt = pow(26,len1) * (pow(26, len2 - len1 + 1)-1)/25;
return rt;
}
int calbigger(char* str,int strLen,int len1,int len2){
int count = 0;
int tail = (len2 - strLen) > 0 ? strLen -1: len2 - 1;
if (len2 > strLen)
{
count += calsubstring(1, len2 - strLen);
}
for (int i = tail; i >= 0;i--)
{
int start = (i + 1 - len1) > 0 ? 0 : len1 - (i + 1);
count += ('z' - str[i])*calsubstring(start, len2 - i-1);
}
return count;
}
int main(){
int len1 = 0, len2 = 0;
char str1[110] = { 0 };
char str2[110] = { 0 };
while (scanf("%s %s %d %d",str1,str2,&len1,&len2)!=EOF){
int str_len1 = strlen(str1);
int str_len2 = strlen(str2);
int rt = calbigger(str1, str_len1, len1, len2) - calbigger(str2, str_len1, len1, len2);
printf("%d\n", rt-1);
}
return 0;
}
# include<bits/stdc++.h>
using namespace std;
int main()
{ string s1,s2; int l1,l2; while(cin>>s1>>s2>>l1>>l2) { s1.append(l2-s1.length(), 'a'); s2.append(l2-s2.length(), (char)('z'+1)); vector<int> v; for(int i=0;i<l2;i++) v.push_back(s2[i]-s1[i]); int result = 0; for(int i=l1;i<=l2;i++) for(int j=0;j<i;j++) result += v[j]*pow(26,i-1-j); cout<<result-1<<endl; } return 0;
}
/*
题目描述
求字典序在s1和s2之间的,长度在len1到len2的字符串的个数,结果mod 1000007。
输入描述:
每组数据包涵s1(长度小于100),s2(长度小于100),len1(小于100000),len2(大于len1,小于100000)
输出描述:
输出答案。
示例1
输入
ab ce 1 2
输出
56
思路
采用27进制的想法,位数不足补'a'-1,位数超出则截取
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
#define N 1000007
int main(){
string s1,s2;
int l1,l2;
while(cin>>s1>>s2>>l1>>l2){
string temp;
if(s1>s2){
temp=s1;
s1=s2;
s2=temp;
}
if(s1.length()<l2)
s1.append(l2-s1.length(),'a'-1);
else
s1=s1.substr(0,l2);
if(s2.length()<l2)
s2.append(l2-s2.length(),'a'-1);
else
s2=s2.substr(0,l2);
int a[l2];
for(int i=0;i<l2;i++){
a[i]=s2[i]-s1[i];
}
int res=0;
for(int i=0;i<=l2-l1;i++){
for(int j=0;j<l2-i;j++)
{
double t=a[j]*pow(26,l2-i-j-1);
res+=t;
if(res>=N)
res=res%N;
}
}
cout<<res-1<<endl;
}
return 0;
}
def gc(i, A):
return ord(A[i]) if i < len(A) else 96
while 1:
try:
s = raw_input()
except:
break
s1, s2, l1, l2 = s.split(' ')
d, s, l1, l2 = 0, 0, int(l1), int(l2)
for i in range(l2):
a, b = gc(i, s1), gc(i, s2)
d = (26 * d + b - a) % 1000007
if i == len(s2) - 1:
d -= 1
if i >= l1 - 1:
s = (s + d) % 1000007
print s
int main (int argc, char** argv) {
string s1, s2;
int len1, len2;
//scanf("%s %s %d %d", &s1, &s2, &len1, &len2);
cin >> s1 >> s2 >> len1 >> len2;
char ch1 = s1[0];
char ch2 = s2[0];
LL res = 0;
for (int i = len1; i <= len2; ++i) {
res += (ch2 - ch1) * pow(26, i-1);
LL sum = 0;
for (int j = 1; j < s2.size(); j++) {
char temp = 0;
if (j > s1.size()-1) {
temp = 'a';
} else {
temp = s1[j];
}
sum += (s2[j] - temp) * pow(26, i-j-1);
}
res += sum;
}
res--;
cout << res%1000007 << endl;
return 0;
}
根据前面回答,仿制写的,想了好一阵子才想明白。。。
#include<iostream>
#include<string>
using namespace std;
void add_(string& s,int len){//模拟字符串s加一
//不用考虑溢出因为函数调用前限制了条件
if(len <= 0){
return ;
}
if( s[len - 1] == 'z'){
s[len - 1] = 'a';
add_(s,len - 1);
}else{
s[len - 1] = s[len - 1] + 1;
}
}
int get_sum_len(string& s1, string& s2, int len){
//计算 s1 和 s2之间(包含s1,s2)有多少个长度为len的序列
if( len <= 0 || s1 >= s2){
return 0;
}
int count = 1;
while(s1 < s2){
add_(s1, len);
count++;
}
return count;
}
int main(){
string s1,s2;
int len1,len2;
while(cin>>s1 >> s2 >> len1 >> len2){
int sum = 0;
for(int i = len1; i <= len2; i++){
//每次循环计算出有多少个长度为i,在s1和s2之间的序列
string tem1 = s1;
string tem2 = s2;
if(i > tem1.size()){//sum 不变 补a
while( i > tem1.size() ){
tem1 += 'a';
}
}else{//sum减一
sum -= 1;
}
if( i >= tem2.size() ){//sum - 1 补a
while( i > tem2.size() ){
tem2 += 'a';
}
sum -= 1;
}
tem1 = tem1.substr(0,i);//截断
tem2 = tem2.substr(0,i);//截断
sum += get_sum_len(tem1, tem2, i);
sum %= 1000007;
}
cout <<sum <<endl;
}
return 0;
} """ 思路:遍历 m-n 位字符串,符合要求的个数是两个字符串的差值 比如 ab ce 1-2 先求 1 位字符串,符合要求的个数 n = 'c' - 'a' // python 用 ord() 获取 ascii 码 求 2 位字符串,符合要求的个数 n = 'ce' - 'ab' = 55 // 字母是 26 个数,不能按照 10 进制计算,而是 26 进制 这样计算的结果包括了 'ce' 最后结果得减 1 """while True: try: s = raw_input() if s == None: break sa, sb, m, n = s.split() la = len(sa) lb = len(sb) sum = 0 for i in range(int(m),int(n)+1): if i>la or i>lb: break t = 0 n = 0 while t<i: tmp = ord(sb[t])-ord(sa[t]) n = (n*26 + tmp)%1000007 t = t + 1 sum = (sum + n)%1000007 print sum - 1 except:break
private static int process(String str1, String str2, int len1, int len2) {
char[] ch1 = str1.toCharArray();
char[] ch2 = str2.toCharArray();
long res = 0;
for (int i = len1; i <= len2; i++) {
char a = ch1[0];
char b = ch2[0];
res += (long) Math.pow(26, i - 1) * (b - a);
long suma = 0;
long sumb = 0;
for (int j = 1; j < ch1.length; j++)// 找到比ch1剩余字符串小的字符串个数
{
suma = suma + (ch1[j] - 'a') * (long) Math.pow(26, i - 1 - j);
}
for (int j = 1; j < ch2.length; j++)// 找到比ch2剩余字符串小的字符串个数
{
sumb = sumb + (ch2[j] - 'a') * (long) Math.pow(26, i - 1 - j);
}
res = res + sumb - suma;
}
res--;
res= res % 1000007;
return (int) res;
}
#include<iostream>
#include<string>
#include<vector>
#include<math.h>
using namespace std;
int main(){
//根据题中给出的例子,这个字符串只包含小写字母,不然答案就不应该是56了
string s1,s2;
int len1,len2;
while(cin>>s1>>s2>>len1>>len2){
//只包含小写字母的字符串可以看成26进制的数制
//将s1和s2补长到len2长度
s1.append(len2-s1.size(),'a');
s2.append(len2-s2.size(),(char)('z'+1));
vector<int> array;
for(int i=0;i<len2;i++){
array.push_back(s2[i]-s1[i]);
}
int result = 0;
for(int i=len1;i<=len2;i++){
for(int k=0;k<i;k++){
result += array[k]*pow(26,i-1-k);
}
}
//所有字符串最后都不包含是s2自身,所以最后要减1;
cout<<result-1<<endl;
}
return 0;
}
/*看了之前50多个答案,发现大部分都是错误的,根据自己对题目的理解,给出了以下思路,目前
我还没有找到bug,欢迎牛友们检查,如有bug,我继续修改,答题思路是对的*/
/*首先是从之前的几个测试样例分析,其中一个为 str1 = cpqejrrgp, str2 = cpqejtrdg,
len1 = 9, len2 = 9,设所求满足情况的字符串代号为 str(str有35064种)。
第一步:首先找到两个字符串相对应位置的第一个不相等的位置,即若ab 和 ce,
第一个相对位置不相等的为值就是下标为0的地方 a 和 c 不一样,str1和str2中第一个相对不相等
的位置是下标为5的地方,即 r 和 t,设下标为k;
第二步:先求在此下标处,字符处于下标位置字符之间的情况,即str[k]>str1[k] && str[k]<str2[k]
的情况,这个最好算,只要k位置大于str1小于str2对应的k位置,后面的任一位置可以随意取,每个
位置有26种,例如str1[5]和str2[5]之间共有num1种(‘t’-'r'-1=1种即为's'这一种情况),
str[5]为s的时候,后面三位可以随意取;共有(str2[k] - str1[k] - 1)*pow(26, i - k)种,
其中i为len1到len2之间的取值,这里用一个for循环累加;
第三步:其次再求str[k]==str1[k]时有多少种,此时,str[k+1]需大于str1[k+1],k+2位,k+3位...
可以随意取,接着再求str[k]==str1[k]&&str[k+1]==str1[k+1]的情况,需str[k+2]大于str1[k+2]
,k+3以及之后的位置随意取,以此类推,直到算到k==len2-1的位置为止;
第四步:最后求str[k]==str2[k]的情况,此时,str[k+1]需要小于str2[k+1],k+2,k+3等之后的
位置随意取,接着再求str[k]==str2[k]&&str[k+1]==str2[k+1]的情况,需要str[k+2]小于str2[k+2],
后面的位置随意取,以此类推,直到算到k==len2-1的位置为止;
第五步:把所有情况相加,注意还有几处边界位置需要处理,具体参考以下代码
*/
#include<iostream>
#include<string>
#include<math.h>
using namespace std;
int main()
{
string str1,str2;
int len1,len2;
while(cin>>str1>>str2>>len1>>len2)
{
if(str1.length()<len2)
str1.append(len2-str1.length(),'a'-1);
if(str2.length()<len2)
str2.append(len2-str2.length(),'z'+1);
long long sum = 0;
int k = 0;
//第一步,找第一个相对位置不相等的位置下标
while(str1[k]==str2[k])
{
k++;
}
if(str1[k]<str2[k] && len1<=len2)
{
//第二步,计算str[k]>str1[k] && str[k]<str2[k]的情况
for(int i= len1-1;i<len2;i++)
{
if(i==k)
{
if(k==len1-1 && k==len2-1)
sum += str2[k] - str1[k] -1;
else
sum += str2[k] - str1[k];
}
else
sum += (str2[k] - str1[k] - 1)*pow(26,i-k);
}
k++;
//第三步,计算str[k]==str1[k]时的情况和str[k]==str2[k]的情况
for(int i = len1;i <= len2;i++)
{ for(int j=k;j<i;j++)
sum += ('z'-str1[j])*pow(26,i-j-1);
for(int j=k;j<i;j++)
sum += (str2[j]-'a')*pow(26,i-j-1);
}
}
cout << sum << endl;//我这里没有对1000007取模,答案也是能过的,牛友们可自行添加
}
system("pause");
return 0;
} import java.util.*;
public class Main{
public static void main(String []args){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
long result = 0;
String begin = sc.next();
String end = sc.next();
int len1 = sc.nextInt();
int len2 = sc.nextInt();
int maxlen = begin.length()>end.length()?begin.length():end.length();
int minlen = begin.length()<end.length()?begin.length():end.length();
for(int i=0;i<maxlen;i++){
int distance;
if(i<minlen){
distance = end.charAt(i)-begin.charAt(i);
}else{
if(begin.length()>end.length())
distance = 'a' - begin.charAt(i)-1;
else
distance = end.charAt(i)-'a'+1;
}
long now=0;
for(int j=len1;j<=len2;j++){
if(j-i-1>=0){
now=now+(long)Math.pow(26,j-i-1);
}
}
now = (now*distance)%1000007;
result+=now;
}
System.out.println(result-1);
}
}
}
这题,根本不用动态规划,净瞎扯……
//想明白了思路就很简单,代码也很少。
//求解大于str1的字符串个数以及大于str2的字符串个数,然后两者相减就能得到处于str1和str2之间的字符串个数
//对于求解长度len在[len1,len2]之间,且字典序大于某个字符串(str)的字符串个数:
//顺序遍历(i=0:n-1)str的每个字符str[i],则若一个字符串destr大于str,则有两种情况:
//(1)destr第i个字符大于str[i],则之后的字符无论是什么,destr都大于str
//(2)destr第i个字符等于str[i],则i++,并继续讨论后续字符
//最后如果len>strLen,需要考虑destr前strLen位和str完全一样,则剩余位置字符可以是任意字符。
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int getcount(char str[], int strLen, int len1, int len2){
int count = 0;
for(int len = len1; len <= len2; len++){
for(int i = 0; i < strLen && i < len; i++)
count += (26 - (str[i] - 'a' +1)) * pow(26,len - i - 1);
if(len > strLen){
count += pow(26,len - strLen);
}
}
return count;
}
int main(){
char str1[120];
char str2[120];
memset(str1,0,sizeof(str1));
memset(str2,0,sizeof(str2));
int len1, len2;
while(cin >> str1 >> str2 >> len1 >> len2){
int strlen1 = strlen(str1);
int strlen2 = strlen(str2);
int count1 = getcount(str1,strlen1,len1,len2);
int count2 = getcount(str2,strlen2,len1,len2);
int count = count1 - count2 - 1;
cout << count << endl;
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int a = 1000007;
const int maxn = 100+5;
int len1, len2, ls1, ls2;
char s1[maxn];
char s2[maxn];
long long ans_arr[100000+1];
int main(){
long long ans = 0;
while(scanf("%s%s%d%d", s1, s2, &len1, &len2) == 4){
ls1 = strlen(s1); ls2 = strlen(s2);
int k = 0;
memset(ans_arr, 0, sizeof(ans_arr));
ans = 0;
while(s1[k] == s2[k]) k++;
ans_arr[k+1] = s2[k] - s1[k];
for(int i=k+2;i<=len2;i++){
int stuff = 0;
if(i <= ls1) stuff += 'z' - s1[i-1];
if(i < ls2) stuff -= 'z' - s2[i-1];
if(i == ls2) stuff -= 'z' - s2[i-1] + 1;
ans_arr[i] = ans_arr[i-1]*26 % a + stuff;
}
for(int i=len1;i<=len2;i++) ans += ans_arr[i];
cout<<ans<<endl;
}
return 0;
}
#include<iostream>
#include<string>
using namespace std;
int main(){
string s1,s2;
int len1,len2;
while(cin>>s1>>s2>>len1>>len2){
int result = 0;
int dp[120];
for(int i=1; i<=len2; i++){
dp[i] = (26*(dp[i-1]))%1000007;
if(i<=s1.size()) dp[i] -= s1[i-1];
if(i<=s2.size()) dp[i] += s2[i-1];
if(i == s2.size()) dp[i]--;
if(i>=len1) result += dp[i];
}
cout<<result%1000007<<endl;
}
return 0;
}
/**
字符串计数:求字典序在s1和s2之间的,长度在len1到len2的字符串的个数,结果mod 1000007。
参照了前几位大牛的代码,并做了稍微的改动。
先举个10进制的例子:
138-->652 的三位数有几个? (6-1)*10^2 + (5-3)*10^1 + (2-8)*10^0 = 5*100+2*10+(-6)*1 = 514 == 652-138
可以看出,514中不包括138,但是包括514,所以大于138小于652的数就是再去掉一个数(652)==652-1=651
如果是四位数呢?那就是1380-->6520之间的数,6520-1380=5140(这里只可以看出,不包含6520,因为字典序中,
652<6520, 但是包括1380,因为字典序中1380>138, 所以,这个5140就四位数的个数。
同样可以分析,18-->656 中1到四位数,这里会发现,
1位数的个数n1就是6-1=5(不包含1,而包含6)
2位数的个数就是n2=n1*10+(5-8) (不包含18,但包含65)
3位数的个数就是n3=n2*10+(6-0) (这里18不够三位数,补上0,变成180, 这里不包含180而包含656,刚才应该不包含656而包含180)
4位数的个数就是n4=n3*10+(0-0) (这里两个数都不足四位数,补0为1800->6560, 不包含1800,而包含6560,实际上应该包含1800而不包含6560,但是对计数没有影响)
同样,字母a-z就是26进制,也这么算。
综上:只有s1的长度和s2的长度相等时,才会多加一个s2,否则不会多加,也就不用减1。
以下测试用例:
a ac 1 2 -->aa, ab -->2
aa ac 2 3 --> ab, aa(a-z), ab(a-z)-->53
牛客网的测试用例不够充分,所以很多情况测不出来。
*/
#include<iostream>
#include<string>
#include<vector>
#include<math.h>
using namespace std;
#define M 1000007
int main() {
#ifdef LOCAL_DEBUG
freopen("input.txt", "r", stdin);
#endif
//根据题中给出的例子,这个字符串只包含小写字母,不然答案就不应该是56了
string s1, s2;
int len1, len2;
while (cin >> s1 >> s2 >> len1 >> len2) {
//只包含小写字母的字符串可以看成26进制的数制
//将s1和s2补长到len2长度
int tlen1 = s1.size();
int tlen2 = s2.size();
s1.append(len2 - s1.size(), 'a');
s2.append(len2 - s2.size(), (char)('a'));
vector<int> array;
for (int i = 0; i < len2; i++) {
array.push_back(s2[i] - s1[i]);
}
int result = 0;
for (int j = 0; j < len1 - 1; j++) {
result = (26 * result + array[j])%M;
}
int sum = 0;
for (int i = len1 - 1; i < len2; i++) {
result = ((26 * result) % M + array[i]) % M;
sum = (sum + result) % M;
}
if (tlen1 == tlen2)
sum = (sum - 1 + M) % M;
cout << sum << endl;
}
return 0;
}