CSP-2

A - HRZ的序列

问题描述

现有一个长度为n的序列,问是否存在这样一个数,使得序列中一些数加上这个数 ,一些数减去这个数,一些数不变,使得整个序列中所有的数相等(其中对于序列中的每个位置上的数字,至多只能执行一次加运算或减运算或是对该位置不进行任何操作)。

Input

输入第一行是一个正整数 t, 表示数据组数。接下来对于每组数据,输入的第一个正整数n表示a序列的长度,随后一行有n个整数,表示a序列 。

Output

输出共包含t行,每组数据输出一行。对于每组数据,如果存在这样的K,输出"YES",否则输出“NO”。(输出不包含引号)

Example

Input

25
1 2 3 4 5
5
1 2 3 4 5

Output

NO
NO

在这里插入图片描述

解题思路

因为要使这个序列的数都相等, 因此最多只能有三个数不相等。所以使用set容器, 将整个a序列存入set< long long int >类型
一定要注意数据范围!!!!
的数组b中,然后查看数组b的size即可。 如果size<=2,那么一定存在所要求的数字;如果size==3,只要满足三个数字的平均值等于b[2],那么就存在这样一个数字,否则不存在;如果 size>=4, 那么一定不存在。

代码

#include <iostream>
#include <cmath>
#include <set>
#include <string.h>
#include <stdio.h>
using namespace std;

long long int a[10010], c[3], min1, max1;
set<long long int> p, q;

int main()
{
	int m, n, status, count, s, m1;
	scanf("%d", &n);
	for(int i=0;i<n;i++)
	{
		status = 0, s = 0;
		scanf("%d", &count);
		p.clear(), q.clear();
		for(int i=0;i<count;i++)
		{
			scanf("%lld",&a[i]);
			p.insert(a[i]);
		}
		set<long long int> ::iterator it = p.begin();
		if(p.size()==3)
		{
			while(it!=p.end())
			{
				c[s++] = *it;
				it++;
			}
			if(c[0]+c[2]==2*c[1])
				status = 1;
		}
		if(status||p.size()<=2)	
			printf("YES\n");
		else
			printf("NO\n");		
	}
	return 0;
}

B - HRZ学英语

问题描述

现在给定一个字符串,字符串中包括26个大写字母和特殊字符 ‘?’ ,特殊字符 ‘?’ 可以代表任何一个大写字母。问是否存在一个位置连续的且由26个大写字母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果不存在,就输出-1!
说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排在前。例如

AB??EFGHIJKLMNOPQRSTUVWXYZ
ABCDEFGHIJKLMNOPQRSTUVWXYZ
ABDCEFGHIJKLMNOPQRSTUVWXYZ

上面两种填法,都可以构成26个字母,但是我们要求字典序最小,只能取前者。
注意,题目要求的是 第一个出现的,字典序最小的!

Input

输入只有一行,一个符合题目描述的字符串。

Output

输出只有一行,如果存在这样的子串,请输出,否则输出-1

Example

Input1

ABC??FGHIJK???OPQR?TUVWXY?

Output1

ABCDEFGHIJKLMNOPQRSTUVWXYZ

Input2

AABCDEFGHIJKLMNOPQRSTUVW??M

Output2

-1

在这里插入图片描述

解题思路

这道题和之前写过的窗口移动比较相似,但是窗口大小是固定的,因此更好处理。所以从i=25开始遍历字符串即可。至于如何判断数组中的26个字母是否各不相同, 则需要开辟一个长度为26的数组来进行统计,也可以通过这个数组来找出 ‘?’ 对应的字母。然后将字符串中 ‘?’ 替换为指定的字母即可。如果替换后得到的字符串中各不相同的字母数等于26, 就输出该字符串;如果直到遍历的字符串尾都找不到符合条件的字符串就输出-1.

代码

#include <iostream>
#include <string.h>
#include <string>
using namespace std;

char a[26]; 

int main()
{
	string s;
	cin>>s;
	int l = 0, r = 25, m = 0, length;
	for(int i=25;i<s.size();i++)
	{
		m = 0;
		length = l+26;
		int b[26] = {0};
		for(int j=l;j<length;j++)
		{
			if(s[j]!='?')
			{
				a[j-l] = s[j];
				b[s[j]-65] = 1;
			}		
		}
		for(int i=l;i<length;i++)
		{
			if(s[i]=='?')
			{
				for(int j=0;j<26;j++)
					if(b[j]==0)
					{
						a[i-l] = j + 65, b[j] = 1;
						break;
					}		
			}		
		}
		l++;
		int sum = 0;
		for(int i=0;i<26;i++)
		{
			if(b[i]==1)
				sum++;
		}
		if(sum==26)
		{
			for(int i=0;i<26;i++)
				printf("%c", a[i]);
			return 0;
		}
	}
 	printf("-1");
 	return 0;
}

C - 咕咕东的奇妙序列

问题描述

112123123412345 …这个序列由连续正整数组成的若干部分构成,其中第一部分包含1至1之间的所有数字,第二部分包含1至2之间的所有数字,第三部分包含1至3之间的所有数字,第i部分总是包含1至i之间的所有数字,11212312341234512345612345671234567812345678912345678910,其中第1项是1,第3项是2,第20项是5,第38项是2,第56项是0。现在想知道第 k 项数字是多少。

Input

输入由多行组成。
第一行一个整数q表示有q组询问(1<=q<=500)
接下来第i+1行表示第i个输入ki,表示询问第ki项数字

Output

输出包含q行
第i行输出对询问ki的输出结果

Example

Input

5
1
3
20
38
56

Output

1
2
5
2
0

在这里插入图片描述

解题思路

因为数据范围比较大,如果一层一层的找想要查找的数字位于第几层,那么会超时。因此,需要二分地进行查找。因此问题关键就在于如何计算当前层级包含的数字总数。具体公式就不详细介绍(从1-9算起,依次计算10-99, 100-999的层级数字数之和。每一级的运算过程是先计算出位数相同的数字的数字数,比如说层级为2时,即当前数字最大为99,计算出层为10-99(他们中两位数的个数为1-90)中的数字之和再乘以2,再加上更高层级中所有位数为2的数字数,由此即可计算出二位数的所有数字个数,以此类推,大致过程就是这样)。
至于每一层的中数字个数,计算过程与上述类似,就不在介绍。然后运用二分的思想即可更快的求出当前层级和具体数字,输出特定的数字即可。

代码

#include <iostream>
#include <stdio.h>
#include <cmath>
using namespace std;

long long int n, m, level, num, s, r, l;

long long int sum(long long int x)
{
    return (x + 1) * x / 2;
}

long long int getsum1(long long int x)
{
    long long int ans = 0, i = 1, j = 1;
    for (i = 1, j = 1; j * 10 <= x; i++, j *= 10)
        ans = ans + i * sum(j * 9) + i * j * 9 * (x - j * 10 + 1);
    return ans + i * sum(x - j + 1);
}

long long int getsum2 (long long int x) 
{ 
	long long int ans=0, i=1, j=1;
	for (i=1, j=1 ; j*10<=x; i++,j*=10 ) {
		ans += i*j*9;
	}
	return ans + i*(x-j+1);
}

int main()
{
    scanf("%lld", &n);
    for (int i = 0; i < n; i++)
    {
        scanf("%lld", &m);
        l = 0, r = 1e9;
        while (l <= r)
        {
            long long int mid = (l + r) / 2;
            if (getsum1(mid) < m)
            {
                l = mid + 1;
                level = mid;
            }
            else
                r = mid - 1;
        }
        m = m - getsum1(level++);
        l = 0, r = level;
        while (l <= r)
        {
            long long int mid = (l + r) / 2;
            if (getsum2(mid) < m)
            {
                l = mid + 1;
                num = mid;
            }
            else
                r = mid - 1;
        }
        m = m - getsum2(num++);
        int a[30] = {0}, j = 0;
        while (num != 0)
        {
            a[j++] = num % 10;
            num = num / 10;
        }
        printf("%d\n", a[j - m]);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值