2020牛客暑期多校训练营(第六场)

总结:
这一次还行,做题前面比较顺利得出了两题,但是后面不是很顺利,团队配合一般需要改进。

E

题意

给你n和k,要求构造一个1-n的数列满足,对任意长度,都存在一个连续区间满足区间和sum%n ==k。若存在则输出这个数列,否则输出-1。

思路

模拟。首先想到的就是先求1-n的和判断是否是k 的整数倍,如果不是则直接输出-1,然后再考虑成立的情况,总共分为两种情况成立:
1.k=0。若k0,则我们可以让n放在开头第一位,之后我们两位两位放,i和n-i,这样保证任意一个长度都能满足题意。
2.k
n/2,那我们把n和k放在开头,之后和上面一样放i和n-i。

代码

#include<bits/stdc++.h>
using namespace std;

int main(){
	int n,k;
	cin>>n>>k;
	if(n&1){
				if(k==0)
			{
				printf("%d",n);
				for(int i=1;i<=n/2;++i)
					printf(" %d %d",i,n-i);
					return 0;
			}
	}
	else 
		if(k==n/2){

				printf("%d %d",n,k);
				for(int i=1;i<n/2;++i)
					printf(" %d %d",i,n-i);
					return 0;
		}
	puts("-1");
	return 0;
}

C

题意

选出一个子矩阵,使得所求的压强最大,压强是指这个子矩阵中每个元素之和 / 这个子矩阵最下面一行的元素之和

思路

只需要维护每一列元素的前缀和,并且在计算的过程中除以当前这个数,这样就OK,记得要维护当前的最大压强值

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read() {
    ll c = getchar(), Nig = 1, x = 0; while (!isdigit(c) && c != '-')c = getchar();
    if (c == '-')Nig = -1, c = getchar();
    while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
    return Nig * x;
}
#define read read()
double a[208][208];
double sum[208];
int main() {
    int T = read;
    while (T--) {
        int n = read, m = read;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) scanf("%lf", &a[i][j]);
        }
        double ans = 0;
        for (int i = 1; i <= m; i++) {
            sum[i] = 0;
            for (int j = 1; j <= n; j++) {
                sum[i] += a[j][i];
                
                double tt = (sum[i]) / (a[j][i]);
                if (tt > ans) ans = tt;
            }
        }

        printf("%.8f\n", ans);
    }
    return 0;
}
/**
1
3 3
1 3 5
6 8 9
2 7 4


**/


G

题意

给你一个n*n的网格,总共k种颜色,给网格的边缘染色;
条件:
1.所有颜色出现相同的次数;
2.不存在单色环;
3.每条水平线或垂直线都应该至少包含两种颜色。
输出每条水平线的颜色和垂直线的颜色,没有则输出-1;

思路

分情况讨论:
1.k%n!=0时,直接1,2,3……k依次放就行了。
2.k%n==0时,如果按照上一种模拟会重复,所以让行加一,这样就会错开,然后按照前一种模拟即可。

代码

#include <bits/stdc++.h>
int main(){
	int te;
    scanf("%d",&te);
while(te--){
	int n,k,p;
    	scanf("%d%d",&n,&k);
		p=0;
	    if(n==1||k==1||2*n*(n+1)%k){puts("-1");continue;}
	    for(int i=1;i<=2*n+2;i++){
	        for(int j=1;j<=n;j++) 
				printf("%d ",p+1),p=(p+1)%k;
	        if(n%k==0) p=(p+1)%k;
			putchar(10);
	    }
    }
}

K

题意

一个序列被称为k-bag,当且仅当其以1-k的数排列组成。例如1,2,3,2,1,3,3,2,1是有效的3-bag序列。部分k-bag序列是指k-bag的连续子序列。
多组数据。给出n,k,给出长度为n的序列,判断该序列是否为部分k-bag序列。

思路

给出序列可能存在序列开头、结尾处残缺的区间。因此需要寻找开始循环的起点,起点在前k个数字中,即起点下标范围为0-(k-1)。p[0]为第一个完整部分k-bag序列的连续子序列的起始下标。len=min(p [0],k-1)。在0-len范围内找起点。
枚举判定起点,有两种情况。如果后面有长度>=k的序列,则每次往后跳k个,即p[j]>=k时。如果后边长度<=k,p[j]+j==n,直接到序列末尾。

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false),cin.tie(0);
#define ll long long
#define inf 0x3f3f3f3f
const int N=5e5+5;
//set<string>b;
//set<string>::iterator it;
int a[N],p[N];
set<int>mp; 
int main()
{
    IO;
    int T,n,k,i,j,x,y,flag,len;
    cin>>T;
    while(T--)
    {
    	mp.clear();
    	x=0;y=0;
		cin>>n>>k;
    	for(i=0;i<n;i++)
    	{
    		cin>>a[i];
		}
		while(x<n)
		{
			while(y<n&&!mp.count(a[y]))
			{
				mp.insert(a[y++]);
			}
			mp.erase(a[x]);
			p[x]=y-x;
			x++;
		}
		flag=0;
		len=min(p[0],k-1);
		for(i=0;i<=len&&flag==0;i++)
		{
			flag=1;
			for(j=i;j<n&&flag;j+=k)
			{
				if(p[j]>=k||p[j]+j==n) continue;
				flag=0;
			}
		}
		if(flag==1)
		{
			cout<<"YES\n";
		}
		else
		{
			cout<<"NO\n"; 
		}
	}
    return 0; 
}

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页