今天,集训队按照acm比赛的流程举行了我们第一次积分赛,无奈,本人太弱,最后滚榜阶段以90人中第48人遗憾结尾,不过最后滚榜的那个过程是真刺激,好多人直接在最后一小时滚到前三十名,羡慕啊.期待自己可以滚到前20的一天,当然最好可以在封榜前就稳居前20最好QAQ;
废话不多说,首先是第一题
第一题是辞树学长出的题,题意是给定一个字符串求字符串中QAQ的数目,这三个字母不一定连续,但是顺序一定是固定的
输入:输入一个整数T(0<=T<=20),代表有T组数据,每组数据会给出一个字符串S,长度为len,len>0,len<=1000000
输出:根据每组字符串,输出QAQ的个数,每组数据换行;
样例
2
QAQAQYSYIOIWIN
QAQQ
输出:4
2
算法核心是把每一个A的左右的q的数量记录在结构体里,然后再对结构体进行便历累加;
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e+6;
const int INF = 0x3ffffff;
//int a[maxn], b[maxn];
char s[maxn];
struct summer
{
int left;
int right;
}oj[maxn];
int main()
{
int T;
cin >> T;
while (T--)
{
//long long num = 0;//这是我个人的坏毛病,一看数据有好多0就想开long long,其实分析一下,len<=1e+6,这也就代表着a的数量q的数量不会超过1e+6,int完全可以处理;
int num=0;
int p = 0;
//long long n;
int n=strlen(s);
memset(s, 0, sizeof(s));//对于定义是全局变量的或者重复使用的切记使用前清0;
scanf("%s", s);
getchar();//抄的学长的代码,学到一个好习惯,吞回车,防止下文cin或者其他字符读入出现问题,应该学习牢记;
n = strlen(s);
for (int i = 0; i < n; i++)//这一步就是先读取每一个A左边的Q的数量
{
if (s[i] == 'Q') num++;
if (s[i] == 'A') oj[p++].left = num;
}
num = 0;//不要忘了清0,小细节;
//long long temp = p - 1;
int temp=p;
for (int i = n - 1; i >= 0; i--)//逆序读取每一个A右边的Q
{
if (s[i] == 'Q') num++;
if (s[i] == 'A') oj[temp--].right = num;
}
long long final = 0;;
for (int i = 0; i < p; i++)
{
final += oj[i].left*oj[i].right;
}
cout << final << endl;
}
//system("pause");
return 0;
}
B题太水,就不上代码了,直接过;
C题
简单的划分题(学长的原话)
大意是给你一组数和分组数,在不改变数组内元素的顺序下,使得分组内最小的的那个数是最大;
这道题啊,好可惜我在分组数为2时一心纠结于数组中的最大值和最小值,从而导致偏离了正确算法
下面附上代码
#include<bits/stdc++.h>
using namespace std;
int a[100005],b[100005];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,k;
while(cin>>n>>k)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b,b+n);
if(k==1)
printf("%d\n",b[0]);
else if(k==2)
{
int p=max(a[0],a[n-1]);
printf("%d\n",p);
}
else
printf("%d\n",b[n-1]);
}
return 0;
}
也许你有疑问为什么在k==2时,只需要比较两端的值:首先当分组数为2时,两个端点一定是分别在两组中,
a b c d e f
假设 :a b c是一组 d e f是另一组;
且c是第一组最小,e是第二组最小
那么也就意味着a>c b>c: d>e f>e;
这时把数组扩展 a b c d:e f
那么第一组的最小值只能是c或者d,而第二组最小值仍是e
假设d<c 那么可以得到a>c>d>e;f>e 那么这组数的最大值只能是f
如果假设d>c::那么第一组的最小值是c,第二组最小值是e,但f>e,所以继续扩展,继续假设c>f,那么我们就可以
得出,第一组的最大值只能是a自己为一个数组时,因为b一定是和其他的在一起,如果b>a,那么第一组还是a,如果小于a,那么直接让a自己一组
所以只许比较两个端点值;
D题
题目太长,我连说都不想说,算了还是要干啊!!
题意:
现有某个协会,为了选定人才,定了如下规则:每个人都会有一个码值有字符串组成,p为字符串中,“NHK”的个数,可以不连续,在字符中的顺序无所谓。Q为改变系数,若某个人的p<k,且Q<L那么这个人就被选拔进去(k和L都为常数)计算出每个选拔进的人的x=p*(L-Q) 找出这些人之后,按照一下顺序排序,对于x相同的人来说按照姓名字典序来最小排,否则按x降序排序
题意大概如此,原题目描述十分羞耻。
输入
T组数据,第二行输入K L M ,K,L以此对应着题目中的K,L。M表示一共M个人然后M行每行输入每个人的信息以此为姓名,特征码,改变系数Q。姓名是长度不超过20的字符串,特征码是长度不超过1000的字符串,输入的数值均为正整数。1<=M<=100,1<=L<=100,1<=k,q<=10;
输出
对于排好序且满足条件的人按照姓名分别输出一行如果没有则输出“FINE”输出不包含引号
输入样例
2
3 28 3
SAKI DDDDD 4
ABB NDSHKHHKKNN 3
BCC HHKKNN 5
4 36 3
SATO NHKNHKNHKNHK NHK NHK 1
QUEEN NHKNHKQRNRHRHNRKHNK 8
DIOOO WRYYYYYNHKNHKNHKKHNNHK 5
输出样例
FINE
SATO
DIOOO
QUEEN
其实这道题现在心平气和的去读,发现只是一个简单的水题,无奈当时比赛时,被B题的格式卡了我wa10次,心态大崩;看到这题题目太长直接跳过,后来再过一遍题时在c题因为实力和思维的落后在k=2卡到结束,
附代码,如果有不懂的,可以私信。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
struct node{
char name[25];
char val[1005];
int id;
int cnt;
int ck;
}a[105],b[105];
bool cmp(node a,node b){
if (a.ck == b.ck) return strcmp(a.name,b.name)<0;
else return a.ck > b.ck;
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while (T--){
int k,l,m;
scanf("%d%d%d",&k,&l,&m);
for (int i = 0;i < m; ++i){
scanf("%s%s%d",a[i].name,a[i].val,&a[i].id);
}
int o = 0;
for (int i = 0;i < m; ++i){
int len = strlen(a[i].val);
int N,H,K;
N = H = K = 0;
for (int j = 0; j < len; ++j){
if (a[i].val[j] == 'N') N++;
if (a[i].val[j] == 'H') H++;
if (a[i].val[j] == 'K') K++;
}
a[i].cnt = min(N,min(H,K)); //NHK出现次数
if (a[i].cnt > k && a[i].id < l){ //P>K 且 Q < L
b[o].cnt = a[i].cnt;
b[o].id = a[i].id;
strcpy(b[o].name,a[i].name);
strcpy(b[o].val,a[i].val);
b[o].ck = b[o].cnt*(l-b[o].id);//P*(L-Q)
o++;
}
}
if (o == 0) printf("FINE!\n");
else{
sort(b,b+o,cmp);
for (int i = 0;i < o; ++i){
printf("%s\n",b[i].name);
}
}
}
return 0;
}
E题
题目:
首先附上出题学长的一句话出自雪中悍刀行-----人生当苦无妨,良人当归即好;
我们现在有很多很多数字,现在我们想知道这个数字有多少个P,S
我们定义P的含义为大小相同的两个数字的个数,例如一组数字里面有两个1,那么这两个一就是一个p,四个1就是两个p。s的含义是连续的三个数字,例如1,2,3就是一个s。请得到最多的p和s的输出
输入
第一行T组数据,第二行n,第三行输入n个数字x x范围(1,n)。
输出
输出最多的P+S
input
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
output
2
4
3
2
线索对于第一组是(1,2,3)(4,5,6);
第二组1,2,3:1,1:2,2:3,3;
第三组2,2:3,3:3,3
第三组2,2:3,3;3,3
第四组1,2,3:3,4,5;
在晚上讲解时,学长原话:你们a这道题这么少?这就是一道简单的贪心啊,这只是我比赛时一道签到题;学长,是我太菜了,我会努力的。
代码
#include <bits/stdc++.h>//本题的思路是优先考虑p,因为p只需要消耗两个数字,而s则需要消耗
//三个数字,所以消耗的数字越少,越可能使和变得越大
using namespace std;
#define f first
#define s second
const int MAXN = 1e5+10;
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
ios::sync_with_stdio(false);//传说中的使cin变得和scanf一样快的的代码,据说竞赛选手必备?
int T;
cin >> T;
while(T--) {
int n, x;
cin >> n;
map<int, int> mp;
for(int i = 1; i <= n; ++i) {
cin >> x;
mp[x]++;//把每个数字的多少储存起来,方便计算p的个数
}
int ans = 0;
for(int i = 1; i <= n; ++i) {
if(mp[i] >= 2) {
ans += mp[i]/2;
mp[i] %= 2;再计算完当前数字可以产生的p的个数后,不要忘了把它磨掉;
}
if(mp[i] && mp[i+1]&1 && mp[i+2]) {//还是优先考虑p,如果这一串连续的数中有偶数个,那么优先考虑消p而不是s,i+1要判断奇偶是因为是奇数个还好,直接顺子,如果是偶数个,按理说不应该拆开,但是硬拆开的话,则会导致后面的几个数也会被拆开,这样是不值得的。
ans++;
mp[i]--, mp[i+1]--, mp[i+2]--;
}
}
cout << ans << endl;
}
return 0;
}
G题
题意:
一共有n个人,每个人的序号从1->n;现在得知k个人的的默契程度是k个人的最大公约数,求这n个人的最大默契值
输入
多组输入,两个空格分开的正整数n和k。(n>=k,k>=1)
输出
一个整数,最大默契值
input
4 2
output
2
另外,对于100%的数据k<=1e+9,n<=1e+9;
思路解释;其实可以想到对于这k个人,他们既然有最大公约数在假设不是1的前提下,他们一定都是某个数字的几倍的关系,比如2,4,6;这三个人都是2的倍数,所以默契值就为2,所以可以想到这n个人中的最大默契值就是从n开始,看看能否整除k如果可以那么n/k的值就是最大默契度
代码
#include<cstdio>
int main()
{
long long n,m;
while(~scanf("%lld%lld",&n,&m)){
printf("%lld\n",n/m);
}
return 0;
}
H题,会长出的一道题
y1=kx1
y2=kx2
z=min(y1*y2/k^2);
求z
可以从题目看出y1和y2是有公约数k的,然后把y1,y2带入z的式子中,得到z=x1*x2,x1,x2分别等于y1/k,y2/k,所以求z的最小值就是求k的最大值,也就是求y1,y2的最大公约数;
代码
#include <bits/stdc++.h>
using namespace std;
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("in.txt", "w", stdout);
int a, b;
bool flag = false;
while(scanf("%d%d", &a, &b) != EOF) {
if(flag) puts("");
else flag = true;
int d = gcd(a, b);
printf("%lld", 1LL * a * b / d / d);
}
return 0;
}
来了,接下来这道题一直到最后都无人ac,各位大佬都栽在超时上,一时间,集体WA成自闭;
I
题意
有一个由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;
input
1
2
3
output
YES 1
在赛后讲解时,大概懂了这道题的思路,:就是对于所给的数组,在判断升序还是降序后分析各自的情况
对于升序,一共有三种情况,分别是在第一个点前,在两点中间,在第三个点后
对于降序,也是这样;
代码
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
LL a[MAXN];
int main() {
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n, T;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i = 1; i < n; ++i) scanf("%lld", &a[i]);
if(n == 1) puts("YES 1");
else if(n == 2) {
if(a[1] == 1) puts("YES 2");
else puts("YES 1");
}
else if(n == 3) {
LL cnt = -1;
LL ans = a[2] - a[1];
if(ans > 0) {
if(a[1] - ans > 0 && a[1] - ans != ans) cnt = a[1] - ans;
else if(ans % 2 == 0 && a[1] - ans / 2 != 0) cnt = a[1] + ans / 2;
else if(a[1] - ans != 0) cnt = a[2] + ans;
}
else if(ans < 0) {
if(a[2] + ans > 0) cnt = a[2] + ans;
else if(ans % 2 == 0) cnt = a[1] + ans / 2;
else cnt = a[1] - ans;
}
if(cnt == -1) puts("NO");
else printf("YES %lld\n", cnt);
}
}
return 0;
}
J题
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
代码
#include<cstdio>
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
int m,n;
scanf("%d",&T);
while(T--){
scanf("%d%d",&m,&n);
if(m>n){//先交换顺序,确保后面的比较,统一;
int t=m;
m=n;
n=t;
}
if(n<=2*m){根据题意可以得出,落后的一方的二倍姚明等于另一方,要么比另一方大。且两者之和一定是三的倍数;
if((m+n)%3==0){
printf("Yes\n");
}else{
printf("No\n");
}
}else{
printf("No\n");
}
}
return 0;
}
啊,总结完发现昨天的比赛考的更多是数学思维,而不是技巧之类的,这也是以后要加强锻炼的,要学会从数学的角度来思考问题,从更高的层面来处理问题;
2018/7/23 宿舍 大晴