总结:
这一次还行,做题前面比较顺利得出了两题,但是后面不是很顺利,团队配合一般需要改进。
E
题意
给你n和k,要求构造一个1-n的数列满足,对任意长度,都存在一个连续区间满足区间和sum%n ==k。若存在则输出这个数列,否则输出-1。
思路
模拟。首先想到的就是先求1-n的和判断是否是k 的整数倍,如果不是则直接输出-1,然后再考虑成立的情况,总共分为两种情况成立:
1.k=0。若k0,则我们可以让n放在开头第一位,之后我们两位两位放,i和n-i,这样保证任意一个长度都能满足题意。
2.kn/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;
}