A 辞树的QAQ水题
时间限制 1s 内存限制 512Mb
蒟蒻的辞树又被吊打了嘤嘤嘤。留下了属于弱者的眼泪QAQAQAQAQAAQAAQA······ 现在我 们定义辞树的悲伤值 F 。F的值为主串中子序列为”QAQ”的个数。注意字母“QAQ”不一定是 连续的,但是字母的顺序应该是准确的。
输入
输入一个整数T(0 ≤ T ≤ 20),代表有T组数据。每组数据会给出一个字符串S,长度为len,0 < len ≤ 1000000 输出 根据每组的字符串,输出辞树的悲伤值F,每组数据换行。
输入样例
2
QAQAQYSYIOIWIN
QAQQ
输出样例
4
2
思路:题意很明显,寻找有多少个不同的QAQ组合,因此我们只需要寻找每个A前后的Q的个数sum1,sum2然后相乘求和即可得到最终答案
代码如下:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
long long sum,n,i,j,sum1,sum2,q,len;
int y[1000010]={0},t;
char str[1000010];
scanf("%d",&t);
while(t--)
{
scanf("%s",str);
sum2=0;
sum1=0;
len=strlen(str);
for(i=0;i<len;i++){
if(str[i]=='Q')
sum1++;
if(str[i]=='A')
y[sum2++]=sum1;
}
sum=0;
for(i=0;i<sum2;i++)
sum+=y[i]*(sum1-y[i]);
printf("%lld\n",sum);
}
return 0;
}
B 排序去重
时间限制 1s 内存限制 512Mb
用计算机生成了N个1到1000之间的随机整数(1≤N≤1000 ),对于其中重复的数字,只保留一 个,把其余相同的数去掉,然后再把这些数从小到大排序。
输入
多组输入,有2行,第1行为1个正整数,表示所生成的随机数的个数: N
第2行有N个用空格隔开的正整数,为所产生的随机数。
输出
也是2行,
第1行为1个正整数M,表示不相同的随机数的个数。
第2行为M个用空格隔开的正整 数,为从小到大排好序的不相同的随机数
输入样例
15 5 8 55 2 6 4 7 56 47 18 222 546 254 56 32
输出样例
14 2 4 5 6 7 8 18 32 47 55 56 222 254 546
思路:这个题直接用set函数就可直接水过(下面是比赛代码,没用set函数)
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int a[10000],n,i,sum;
while(~scanf("%d",&n))
{
sum=n;
for(i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
for(i=1;i<n;i++)
if(a[i]==a[i-1])
sum--;
printf("%d\n",sum);
for(i=0;i<n;i++)
if(a[i]!=a[i-1])
printf("%d ",a[i]);
printf("\n");
}
return 0;
}
C 简单的划分问题
时间限制 1s 内存限制 512Mb
A国有一支由n个人组成的小队,小队中每个人的位置是固定的,并且每个人都有对应的能力 值,这些人的能力值构成一个序列,现在A国要将这一支小队分为x个小组,并对这x个小组进 行能力分析,这x个小组每个小组都有一个最低能力值,一共x个,问怎样划分才能使这x个能力 最弱的人中能力值最高的那个人的能力值最大,并输出这个最大值
输入
多组输入,处理到文件结束
第一行输入n和x,1 < n <= 1500, 1 <= x <= n <= 1500,代表人数和要划分的组数
第二行输入n个整数,代表n个人的能力值 输出 最大的能力值
输入样例
8 1 1 2 3 4 5 9 3 6
输出样例
1
输入样例
7 6 997 425 851 236 789 527 195
输出样例
997
注意
划分小组时人的位置顺序不能改变
思路:当x=1时,只能分成一整份,所以结果肯定是这组数据中的最小值;
当x>=3时,我们直接把这组数中的最大值分成一份,那这个最大值即为它所在这组中的最小值,因此直接输出最大值即可。
当x=2时,分类讨论,若最大值在数组开始或结尾,则可以把最大值分为一组,输出最大值,若最大值在数组中间则只需要判断开头和结尾那个数字更大即可。
例如 按照从小到大排列,第一个数字在这个数组里面第K小,第二个数字在数组里面第k+1小,如果将第一个数字分为一组,则结果为第K-1小的数字(K!=1),若第一二个数字分为一组,结果依然为第K-1小的数字。
若第一个数字在这个数组里面第K小,第二个数字在数组里面第k-1小,如果将第一个数字分为一组,则结果为第K-1小的数字(K!=1),若第一二个数字分为一组,那么结果将变成第K-2小的数字(K!=2),所以要将第一个数字分为一组。最后一个数字的情况一样,所以我们只要找到两端最大的数字,分为一组,即为最终答案。
代码如下:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int a[10000],n,i,j,max,pos,min,x;
while(~scanf("%d %d",&n,&x))
{
max=0;
min=1e9;
for(i=0;i<n;i++){
scanf("%d",&a[i]);
if(min>a[i])
min=a[i];
if(max<=a[i]){
max=a[i];
pos=i;
}
}
if(a[0]==max)
max=a[0];
if(x==1)
printf("%d\n",min);
else if(x==2){
if(max==0 || max==n-1)
printf("%d\n",max);
else
printf("%d\n",a[0]>a[n-1]?a[0]:a[n-1]);
}
else
printf("%d\n",max);
}
return 0;
}
D NHK协会的阴谋
时间限制 1s 内存限制 512Mb
“阴谋啊,这一定是NHK协会的阴谋”
事实上,NHK协会是真实存在的,NHK协会会为每个人分配一个特征码(只包含大写字母的 字符串)以及一个改变系数Q。然后NHK协会会根据以下规则将满足条件的人列为NEET:规定特 征码中所有的0N0 , 0 H0 , 0 K0最多能组合成”NHK”的个数为P 。要求1.P > K 2.Q < L; K, L是常 数。找出真正的NEET之后,对这些人按以下规则排序:对每个人计算出X = P ∗(L−Q),按X由 大到小对这些人进行排序,对于X相同的人按照姓名字典序最小排序,保证给出的姓名都不相 同。
输入
T(1 ≤ T ≤ 100)组数据第二行输入K, L, M,K, L依次对应题目描述中的K, L。 M表示一共M个 人然后M行每行输入每个人的信息依次为姓名,特征码,改变系数Q. 姓名是长度不超过20的字符 串,特征码是长度不超过1000的字符串,输入的数值均为正整数。 1 ≤ M ≤ 100, 1 ≤ L ≤ 100, 1 ≤ K, Q ≤ 10
输出
对排好序且满足条件的人的姓名分别输出一行如果没有NEET则输出”F INE!”输出不包含引号
输入样例
2
3 28 3
SAKI DDDDD 4
ABB NDSHKHHKKNN 3
BCC HHKKNN 5
4 36 3
SATO NHKNHKNHKNHKNHKNHK 1
QUEEN NHKNHKQRNRHRKHNRKNHK 8
DIOOO WRYYYYYNHKNHKNHKKHNNHK 5
输出样例
FINE!
SATO
DIOOO
QUEEN
思路:这个题题目很繁杂冗长,但是意思很明确,对于每个样例,先计算每个人的X值如果至少有一个人符合,就接下去进行。
然后根据每个人的X值排序,X值相同按照名字字典序排序即可。
代码如下:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct xxx
{
char name[1000];
char te[1000];
int q;
int N;
int H;
int K;
int p;
int x;
}a[1000];
int cmp(xxx i,xxx j)
{
if(i.x==j.x)
return strcmp(i.name,j.name)<0;
return i.x>j.x;
}
int main()
{
int t,n,i,j,k,l,m,len,sum;
scanf("%d",&t);
while(t--)
{
sum=0;
memset(a,0,sizeof(a));
scanf("%d %d %d",&k,&l,&m);
for(i=0;i<m;i++)
{
scanf("%s %s %d",a[i].name,a[i].te,&a[i].q);
len=strlen(a[i].te);
for(j=0;j<len;j++)
{
if(a[i].te[j]=='N')
a[i].N++;
if(a[i].te[j]=='H')
a[i].H++;
if(a[i].te[j]=='K')
a[i].K++;
}
a[i].p=a[i].H>a[i].K?a[i].K:a[i].H;
a[i].p=a[i].p>a[i].N?a[i].N:a[i].p;
a[i].x=a[i].p*(l-a[i].q);
if(a[i].p>k && a[i].q<l)
sum++;
}
if(sum==0)
{
printf("FINE!\n");
continue;
}
sort(a,a+m,cmp);
for(i=0;i<m;i++)
{
if(a[i].p>k && a[i].q<l)
printf("%s\n",a[i].name);
else
continue;
}
}
return 0;
}
E Pair and Straight
时间限制 3s 内存限制 32768kB
人生当苦无妨,良人当归即好。
—《雪中悍刀行》
我们现在有很多很多很多数字,现在我们想知道这些数字里面有最多有多少个 P 与 S。
我们定义 P的含义为大小相同的两个数字的个数,例如一组数字里面有两个1 那么这两个1就 是一个P,四个1,那么就是2个P。 S的含义为连续的是三个数字,例如1, 2, 3就是一个S。 还请acmer 请将可以得到的最多的P与S输出
输入
第1行输入T(1 ≤ T ≤ 20)组数据
第2行输入n(1 ≤ n ≤ 1e5)
第3行输入n个数字x(1 ≤ x ≤ n)
输出
输出最多的 P + S
输入样例
4
7
1 2 3 4 5 6 7
9
1 1 1 2 2 2 3 3 3
6
2 2 3 3 3 3
6
1 2 3 3 4 5
输出样例
2
4
3
2
HINT
Case 1(1,2,3)(4,5,6)
Case 2(1,2,3)(1,1)(2,2)(3,3)
Case 3(2,2)(3,3)(3,3)
Case 4(1,2,3)(3,4,5)
这道题为 2017ACM/ICPC广西邀请赛题目(题面不一样,题目所求结果一样),杭电6188号题目。
思路:这道题目中的每个数字只能使用一次。
有P S 两种组合方式,P需要两个数字,S需要三个数字,所以我们尽可能的将数字都合成P。
当我们从第一个数开始遍历,当第一个数的个数sum1>=2时,我们将其尽可能的合成为P,若剩的还有一个,则判断一下第二个数字的个数是否为奇数,第三个数字的个数是否为0。若第三个数字个数为零,则继续进行for循环。
当第二个数字的个数为2n,若果我们将其拿来用作合成S,则剩余2n-1个,下一步可以在合成n-1个P;但是我们将其用来组成P,则可以组成n个P,而且节省了第三个数的个数(由于第一个数的左边已经没有数字,所以只能和右边的数字结合,根据上述情况,只能将这个数字浪费掉)。
当第二个数字的个数为2n-1,则我们可以直接用来合成S,因为如果我们不用它来合成S,则会有可能将其浪费掉,但是如果用来结合,可能会多加一个S。
代码如下:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int t,n,i,j,res,x;
int num[100010];
scanf("%d",&t);
while(t--)
{
memset(num,0,sizeof(num));
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d",&x);
num[x]++;
}
sort(num,num+n);
res=0;
for(i=0;i<n;i++)
{
if(num[i]>=2){
res+=num[i]/2;
num[i]%=2;
}
if(num[i] && num[i+1]&1 && num[i+1]){
num[i]--;
num[i+1]--;
num[i+2]--;
res++;
}
}
printf("%d\n",res);
}
return 0;
}
F 画线条
时间限制 1s 内存限制 512Mb
zxy无聊的在纸上划着线条,队友不能容忍,于是借机给他出了一个简单的问题,让他把自己画 的n线条选择一部分摆到数轴上,且两两没有重合,然后问他最大的摆放数量k
输入
第一行为一个正整数 n;
在接下来的 n 行中,每行有 2个数 ai,bi描述每条线段。
n, ai, bi(0 < n, ai, bi ≤ 106 )
输出
输出一个整数,为 k的最大值。
输入样例
3 0 2 2 4 1 3
输出样例
2
思路:这道题是很经典的贪心算法题目,可以参考杭电2037号题目。
这个题目的思路为将所有线条按照bi从小到大排列,如果bi相同则按照ai大小排序,然后直接遍历即可。
代码如下:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct name
{
int x;
int y;
}a[1000010];
int cmp(name i,name j)
{
if(i.y==j.y)
return i.x<j.x;
return i.y<j.y;
}
int main()
{
int n,i,j,q,sum;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d %d",&a[i].x,&a[i].y);
sort(a,a+n,cmp);
q=a[0].y;
sum=1;
for(i=1;i<n;i++)
{
if(a[i].x>=q)
{
q=a[i].y;
sum++;
}
}
printf("%d\n",sum);
return 0;
}
G 又是毕业季
时间限制 1s 内存限制 512Mb
为了把毕业晚会办得更好,老师想要挑出默契程度最大的k个人参与毕业晚会彩排。可是如何挑 呢?老师列出全班同学的号数1,2,……,n,并且相信k个人的默契程度便是他们的最大公约数 (这不是迷信哦 )。这可难为了他,请你帮帮忙吧!
PS:一个数的最大公约数即本身。
输入
多组输入,两个空格分开的正整数n和k。(n大于等于k,k大于等于1)
输出 一个整数,为最大的默契值。
输入样例
4 2
输出样例
2
提示
对于20%的数据,k小于等于2,n小于等于1000
对于另30%的数据,k大于等于10,n小于等于100
对于100%的数据,k小于等于1e9,n小于等于1e9(神犇学校,人数众多)
思路:这道题目也算是比较水的题目,就是求k个数的最大公约数,直接求n/k即可。
假设n=10,k=2;
如果最大公约数为1,则可能的人为1 2 3 4 5 6 7 8 9 10。(暂时不考虑选的k个数字有更大的公约数的情况)
如果最大公约数为2,则可能的人为2 4 6 8 10。
如果为3,则可能的人为3 6 9。
如果为4,则可能的人为4 8。
如果为5,则可能的人为5 10。
如果为6,则可能的人数为6。个数小于k值,因此结果就为5。
多试几组数据后就能找到规律。
代码如下:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int n,k;
while(~scanf("%d %d",&n,&k))
printf("%d\n",n/k);
return 0;
}
H X and Y
时间限制 1s 内存限制 512Mb
已知:
给定 y1, y2 求 z
输入
多组输入,每行输入两个数字:y1, y2,请求到文件结束(EOF)
0 < y1, y2 < 2 31
输出
每行输出一个整数 z ,
最后一组输出数据末尾没有换行符
输入样例
3 2
3 5
2 7
输出样例
6
15
14
思路:也算是简单的题目,根据公式,这个题目就是求y1*y1/gcd(y1,y2)^2.
代码如下:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int find(int y1,int y2)
{
return y2?find(y2,y1%y2):y1;
}
int main()
{
long long y1,y2,z,x;
while(~scanf("%lld %lld",&y1,&y2))
{
if(y1>y2)
printf("%lld\n",y1*y2/find(y1,y2)/find(y1,y2));
else
printf("%lld\n",y1*y2/find(y2,y1)/find(y2,y1));
}
return 0;
}
I Sequence Of Number
时间限制 1s 内存限制 512Mb
有一个由n个数组成的数列,但其中缺少一项,请你任意添加该项,使整个数列的值y和下标x (1 : n)满足函数:y = kx + b. 其中k, b是不为0的整数.
如果满足,输出YES,并输出数列缺少的那一项的最小值,否则,输出NO.
ps: 数列是由一列有序的正整数组成的连续数字.
输入
第一行一个T,表示T组测试数据.(1 ≤ T ≤ 100)
每一组数据分两行,第一行一个整数 N,第二行是由N −1个数组成的正整数数列. (1 ≤ N ≤ 3)
输入的所有数据不超过int,且为正整数.
输出
若满足输出YES,并输出数列缺少的最小数字,否则输出NO.
需要注意的有一点,虽然输入不超过int,但是输出时可能超过int的,所以我们写代码时需要用long long
输入样例
1
2
3
输出样例
YES 1
样例解释
输入数3的下标可能是1 or 2,当是1的时候,缺项可以是1 2 4 5 7...取最小值为1;当下标为2的 时候,缺项可以是1 2 4 5 6 7...取最小值为1;
思路:这个题意很明显,求满足方程 y=k*x+b 的 y 值 ( k != 0, b != 0 )。
当n=1等于1,x=1,因此如果y值等于1则方程就为y=x,那么b=0,不符合题意。因此结果为2.
当n等于2时,输入的数的x=1或x=2。
假设输入的数为1,如果其对应的x=1,那么结果可能是3,4,5,......如果其对应的x=2,那么结果可能是2,3,4,....因此最终结果为2;
如果输入其他的数n,则数组就可以写为{n,1},k,b肯定不为零,因此结果为1。
当n=3时,情况有七种:
当第一个数大于第二个数,k<0,对应下标可能为1,2或2,3或1,3。
k<0,函数图像为
必定有解,因此我们指需要按顺序计算一下下标为1,2 1,3 2,3的情况即可。
当第一个数等于第二个数时,不符合题意 输出NO
当第一个数字小于第二个数字时,k>0,对应下标可能为1,2或2,3或1,3。
函数可能的图像为
因此我们在按照下标为2,3 1,3 1,2 的顺序计算结果时必须同时考虑b=0的情况。
代码如下:
#include<stdio.h>
int main()
{
long long n,t,i,a[10],res;
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&n);
for(i=0;i<n-1;i++)
scanf("%lld",&a[i]);
if(n==1)
res=2;
else if(n==2){
if(a[0]==1)
res=2;
else
res=1;
}
else if(n==3){
if(a[0]==a[1])
res=-1;
else if(a[0]<a[1]){
if(a[0]*2>a[1] && 2*a[1]!=3*a[0]) res=a[0]-(a[1]-a[0]);
else if((a[1]-a[0])%2==0) res=(a[0]+a[1])/2;
else if(a[0]*2!=a[1]) res=a[1]+a[1]-a[0];
else res=-1;
}
else{
if(a[0]<a[1]*2) res=a[1]-(a[0]-a[1]);
else if((a[0]+a[1])%2==0) res=(a[0]+a[1])/2;
else res=a[0]+(a[0]-a[1]);
}
}
if(res>0)
printf("YES %lld\n",res);
else
printf("NO\n");
}
return 0;
}
J Jack与Pony的战斗
时间限制 1s 内存限制 512Mb
Jack和Pony分别是两股势力的头目,一直以来他们之间总是冲突不断。最近他们又开始了T轮 新的竞争,在每轮竞争中他们会进行多次的PK。在每轮竞争前他们的起始积分都为0,在每 次PK中,赢的一方会加2x积分,输的一方会加x积分(注:x为一个任意正整数)。然后针对 每轮竞争GM会给出两个值m, n,判断经过这轮的多次PK他们两个的积分是否能得到这两个值。 若能得到则输出“Yes”,若不能得到则输出“No”。
输入
输入包含T轮竞争(1 ≤ T ≤ 100)。每轮竞争输入两个整数 m, n(1 ≤ m, n ≤ 10000000)。
输出 对于每轮竞争,若经过数次PK他们两人的积分能得到GM给出的值,则输出“Yes”,否则输出 “No”。
输入样例
3
10 5
121 123
12 100000
输出样例
Yes
No
No
思路:这个题目的要求是每个样例可以进行多次PK,看最终是否能得到所给的结果。
这个情况很少,直接讨论一下就可以。
首先,两个数之间的差值不能超过一倍。假如m>n,则m<=2n。如果不符合,则为NO。
其次,两个数的和必定为三的倍数。
如果符合,假设两个数之间的差值为k=m-n(m>n),设最后一回x为值为K,在在最后一句之前两个人平局,那么倒数第二句两个人的比分为n'=n-(m-n)=2n-m=3n-(n+m),m'=m-(m-n)*2=2n-m=3n-(n-m),恒为3的倍数,因此每次x值都为1,那么必定能达到3n-(n+m)的局面。因此,两个数的和必定为3的倍数,和第二条重复。
所以,最终我们只需要判断前面两个条件即可得出结果。
代码如下:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int t,m,n,i,j,x,y;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&x,&y);
if((x+y)%3!=0)
printf("No\n");
else if(x*2<y || y*2<x)
printf("No\n");
else
printf("Yes\n");
}
return 0;
}