问题 D: 子串
题目描述
给你一个所有字符都是字母的字符串,已知串中任意个连续的字符组成的子序列称为该串的子串。现对于一个字符串中的所有的子串,若将它们中所有的小写字母都转成对应的大写字母(例如,‘a’转换为’A’),大写字母不变,求有多少个子串满足转换后变为"NHOI"(不含引号)。例如,对于字符串"N1H1O1I1", 答案为 0;对于字符串“NHOIhellonhoI”,答案为 2。
输入
输入一行一个字符串。
输出
输出一行一个整数,如题所述答案。
样例输入
hellonhoI
样例输出
1
提示
对于30%的数据,所有字符均为大写。
对于100%的数据,字符串长度小于等于1000000。
//水过水过
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
cin>>s;
int count=0;
for(int i=0;i<s.size();i++)
if(s[i]>='a'&&s[i]<='z') s[i]-=32;
for(int i=0;i<s.size();i++){
if(s[i]=='N'&&s[i+1]=='H'&&s[i+2]=='O'&&s[i+3]=='I')
count++;
}
cout<<count;
return 0;
}
问题 E: 两个数
时间限制: 1 Sec 内存限制: 128 MB
题目描述
现有两个人,若第一个人当前手中的数为 w1,则下一秒他手上的数将会变成m )mod * ( 1 1 1 y w x + ;若第二个人当前手中的数为 w2,则下一秒他手上的数将会变为 m y w x mod ) * ( 2 2 2 + (a mod b 表示 a 除以 b 的余数)。第 0 秒,两个人手上的数分别为 h1,h2。请求出最快在第几秒,第一个人手上的数为 a1,且第二个人手上的数为 a2。若不可能,则输出-1。
输入
第一行为一个正整数T,表示数据组数。
每一组数据第一行为一个正整数m,第二行包括两个整数h1,a1,第三行包括两个整数x1和y1,第四行包括两个整数h2和a2,第五行包括两个整数x2和y2。
输出
对于每一组数据输出一行一个整数,如题所述答案。
样例输入
2
5
4 2
1 1
0 1
2 3
1023
1 2
1 0
1 2
1 1
样例输出
3
-1
提示
对于30%的数据,m<=1000;
对于100%的数据,T<=5,h1不等于a1且h2不等于a2,2<=m<=1000000,0<=h1,a2,x1,y1,h2,a2,x2,y2<m。
题解:关键在于找h变化的循环节,暴力查找即可。找到之后就判断循环节组合起来是否长度相同即可。具体看程序理解。
#include <bits/stdc++.h>
#define ll long long
#define MAXM 1000010
using namespace std;
int T,b[MAXM];
ll m,h,a,x,y,num[2][2];
int main()
{
cin >> T;
while(T--)
{
cin >> m;
for(register int i = 0; i < 2; ++i)
{
cin >> h >> a >> x >> y;
num[i][0] = 0;
num[i][1] = 1;
if(h != a)
{
memset(b, 0, sizeof(int) * m);
b[h] = 1;
while(h != a)
{
++num[i][0];
h = (h * x + y) % m;
if(b[h])
{
num[i][0] = -1;
break;
}
b[h] = 1;
}
}
memset(b, 0, sizeof(int) * m);
h = (h * x + y) % m;
b[h] = 1;
while(h != a)
{
++num[i][1];
h = (h * x + y) % m;
if(b[h])
{
num[i][1] = -1;
break;
}
b[h] = 1;
}
}
if(num[0][0] == -1 || num[1][0] == -1) cout << -1;
else if(num[0][0] == num[1][0]) cout << num[0][0];
else if(num[0][1] == -1 && num[1][1] == -1) cout << -1;
else if(num[0][1] == -1)
{
if(num[0][0] < num[1][0]) cout << -1;
else if((num[0][0] - num[1][0]) % num[1][1]) cout << -1;
else cout << num[0][0];
}
else if(num[1][1] == -1)
{
if(num[1][0] < num[0][0]) cout << -1;
else if((num[1][0] - num[0][0]) % num[0][1]) cout << -1;
else cout << num[1][0];
}
else
{
ll g1 = num[0][1], g2 = num[1][1], g3;
while(g2)
{
g3 = g1 % g2;
g1 = g2;
g2 = g3;
}
if((num[0][0] - num[1][0]) % g1) cout << -1;
else for(register int i = 0; ; ++i)
{
if(num[0][0] + num[0][1] * i < num[1][0]) continue;
if(!((num[0][0] + num[0][1] * i - num[1][0]) % num[1][1]))
{
cout << num[0][0] + num[0][1] * i;
break;
}
}
}
cout << "\n";
}
return 0;
}
问题 F: 取值
时间限制: 2 Sec 内存限制: 128 MB
题目描述
现给你两个正整数n,m。请问有多少种对整数x1,x2,…,xn的取值,使得等式
x1+x2+…+xn=m成立。你的赋值必须满足0≤x1≤x2≤…≤xn。
例如,当m=3,n=2时,共有2种取法,分别为(x1,x2)=(0,3)或(1,2)。请输出答案除以108+7的余数。
输入
第一行为一个正整数T,表示数据组数。
接下来T行,每行两个正整数,分别为m和n。
输出
输出T行,分别表示对每一组数据的答案除以108+7的余数。
样例输入
2
3 2
7 3
样例输出
2
8
提示
对于10%的数据,1<=n<=m<=10;
对于30%的数据,1<=n<=m<=50;
对于50%的数据,1<=n<=m<=100;
对于100%的数据,T<=20,1<=n<=m<=300。
题解:题目要求赋值必须满足0<=x1<=x2…<=xn,因此,对于一种答案序列有两种取法,一种是减小序列长度,即将一位赋为0,另一种是将剩下的位全部增加1个单位,当剩余值=0或者剩余位为1时,就只剩一下一种答案,根据此递归求解即可。
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=305;
const int M=4005;
const int INF=0x3f3f3f;
const ull sed=31;
const int mod=1e8+7;
const double eps=1e-8;
const double PI=acos(-1.0);
typedef pair<int,int>P;
int T,m,n;
int ans[N][N];
int dfs(int x,int y)
{
if(ans[x][y]) return ans[x][y];
if(x==0 || y==1) return 1;
if(x<y) return dfs(x,x)%mod;
return ans[x][y]=(dfs(x,y-1)%mod+dfs(x-y,y)%mod)%mod;
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(ans,0,sizeof(ans));
scanf("%d%d",&n,&m);
printf("%d\n",dfs(n,m)%mod);
}
return 0;
}