UPC 2020年夏混合个人训练第四十八场【D&E&F】

问题 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

米莱虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值