暑假第一场积分赛记录加总结

版权声明:那个,最起码帮我加点人气吧,署个名总行吧 https://blog.csdn.net/qq_41670466/article/details/81159530

今天,集训队按照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    宿舍   大晴

猜你喜欢

转载自blog.csdn.net/qq_41670466/article/details/81159530
今日推荐