7.27 2020牛客暑期多校训练营(第六场)题解及补题
7.27 2020牛客暑期多校训练营(第六场)题解及补题
比赛过程
只出CE两题,1队出5题,还是想的很多都不到位,还总是着急提交代码,忘记了每一次情况后代码得略微修改,消耗罚时。
题解
B Binary Vector
题意
\(n\)个向量线性无关。(每个向量都不属于之前的空间)\(n\)维,一共有\(2^n\)个向量。
求线性无关的概率。
解法
当\(n=1\)时:对于\(a:a,0 (2)\)
当\(n=2\)时:对于\(a,b:a,b,a+b,0 (4)\)
当\(n=3\)时:对于\(a,b,c:a,b,c,a+b,a+c,b+c,a+b+c,0 (8)\)
则有\(f_n=\prod_{i=0}^{n-1} \frac{2^i-1}{2^i}\)
这道题需要知道\(\frac{f_n}{f_{n-1}}=\frac{2^n-1}{2^n}\),\(f_1=\frac{1}{2}\)
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e7 + 5;
const int mod = 1e9 + 7;
long long f[N];
long long p2[N];
long long a[N];
int t, n;
int main()
{
scanf("%d", &t);
f[1] = 500000004; p2[0] = 1;a[0] = 1;
for (int i = 1; i < N; i++)
{
p2[i] = p2[i - 1] * 500000004;
p2[i] %= mod;
a[i] = a[i - 1] << 1;
a[i] %= mod;
if (i >= 2)
{
f[i] = f[i - 1] * (a[i] - 1);
f[i] %= mod;
f[i] *= p2[i];
f[i] %= mod;
}
}
for (int i = 1; i < N; i++)
{
f[i] ^= f[i - 1];
}
while (t--)
{
scanf("%d", &n);
printf("%lld\n", f[n]);
}
}
C Combination of Physics and Maths
题意
选一些行列的子矩阵,价值为\(\frac{F}{S}\),\(F\)代表矩阵值的和,\(S\)代表矩阵底部值的和。求最大价值
解法
只选择一列就好了,从第二行开始,每一行的数字当底,正上面的所有值包括自身是\(F\)
代码
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
using namespace std;
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int inf = 0x3f3f3f3f;
typedef long long ll;
const int maxn = 2000500;
const ll mod = 1e9 + 7;
typedef pair<int,int> pii;
const double pi = acos(-1);
int main() {
IO;
int T;
cin>>T;
while(T--) {
int n,m;
int a[205][205];
int b[205];
cin>>n>>m;
// memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
double ans=0.0;
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
int x;
cin>>x;
b[j]+=x;
double cnt=double(b[j]/(x*1.0));
ans=max(ans,cnt);
}
}
// cout<<ans<<endl;
cout<<fixed<<setprecision(8)<<ans<<endl;
}
return 0;
}
E Easy Construction
题意
给你两个整数\(n\)和\(k\)。求你用 \(1~ n\)构造一个存在$ 1~n \(长度的连续子列都能加起来之和取模\)n\(等于\)k\(,输出能构造出来的集合,如果不能,输出\)-1$。
解法
①n=1的情况下,k=0的情况下就是1,否则就是不能构造;
②n>1并且n&1,k=0的时候,循环输出一头一尾,最后输出n;
③n为偶数就是,k=0的时候,最后输出\(\frac{n}{2}\)和n。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
int n,k;
while(cin>>n>>k){
if(n==1){
if(k==0){
cout<<1<<endl;
}
else{
cout<<-1<<endl;
}
}
else{
if(n&1){
if(k!=0){
cout<<-1<<endl;
}
else{
for(int i=1;i<=n/2;i++){
cout<<i<<" "<<n-i<<" ";
}cout<<n<<endl;
}
}
else{
if(k!=n/2){
cout<<-1<<endl;
}
else{
for(int i=1;i<n/2;i++){
cout<<i<<" "<<n-i<<" ";
}cout<<n/2<<" "<<n<<endl;
}
}
}
}
}
G Grid Coloring
题意
\(n*n\)的格子,\(k\)种颜色,给每一条边染色,要求不存在一行或者一列颜色相同,不存在相同色环,各种颜色使用的数目相同。
解法
构造题
特判一下无解的情况 \(n= 1∣∣k=1∣∣2∗(n+1)∗n mod k ! =0\);
其他情况下,每一行从左到右顺序染色,从左到右对竖边染色,从上到下执行这个过程。
这样可以保证每一行不相同,左右相邻两竖边颜色不同。这样肯定不存在同色环和同颜色的一行。
但是这样每一列相邻两边的颜色间隔为$ 2n+1\(,也就是当满足\)k|(2*n+1) $时,可能出现列的颜色相同。所以我们特判这种情况,当染竖直边的时候,对于奇数行下面的竖直边,往右循环一位染色。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 205;
vector<int>a[maxn],b[maxn];
int n,k;
void Print() {
for(int i = 1;i <= n + 1;i++) {
for(int j = 0;j < a[i].size();j++) {
printf("%d ",a[i][j]);
}
printf("\n");
}
for(int i = 1;i <= n + 1;i++) {
for(int j = 0;j < b[i].size();j++) {
printf("%d ",b[i][j]);
}
printf("\n");
}
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&k);
for(int i = 1;i <= n + 1;i++) {
a[i].clear();b[i].clear();
}
if(n == 1 || k == 1 || 2 * (n + 1) * n % k != 0) {
printf("-1\n");
} else {
int now = 0;
for(int i = 1;i <= n + 1;i++) {
for(int j = 1;j <= n;j++) {
a[i].push_back(now + 1);
now = (now + 1) % k;
}
if(i != n + 1) {
for(int j = 1;j <= n + 1;j++) {
int nex = j;
if((2 * n + 1) % k == 0 && (i & 1)) {
nex = nex % (n + 1) + 1;
}
b[nex].push_back(now + 1);
now = (now + 1) % k;
}
}
}
Print();
}
}
return 0;
}
H Harmony Pairs
题意
解法
代码
//将内容替换成代码
K K-Bag
题意
定义k-bag为一个或多个1-k排列组成的序列,part-k-bag为k-bag的一个连续子序列。给你n个数,问你是不是part-k-bag。
解法
核心思想就是1-k的排列中不可能存在两个相同的数。
用pre[i]表示下标为i的前k个字符有没有重复的,没有则为1,有则为0。
用len[i]表示从下标i开始最多有几个不重复的数。
具体模拟过程看代码注释。
代码
#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(0), cin.tie(0)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 5e5 + 5;
const int inf = ~0u >> 1;
typedef pair<int, int> P;
#define REP(i, a, n) for (int i = a; i < (n); ++i)
#define PER(i, a, n) for (int i = (n)-1; i >= a; --i)
int a[maxn], b[maxn];
int pre[maxn];
int len[maxn];
int main() {
IO;
int t;
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
bool flag1 = true;
REP(i, 1, n + 1) {
cin >> a[i];
b[i] = a[i];
if (a[i] > k) {
flag1 = false;
}
pre[i] = 0;
len[i] = 0;
}
if (!flag1) {
cout << "NO" << endl;
continue;
}
//离散化
sort(b + 1, b + n + 1);
int cnt = unique(b + 1, b + n + 1) - b - 1;
for (int i = 1; i <= n; i++)
a[i] = lower_bound(b + 1, b + cnt + 1, a[i]) - b;
int pos = 1;
REP(i, 1, n + 1) {
while (!pre[a[pos]] && pos <= n) { //如果当前位置的数字没有出现过则记录下来,且继续往后
pre[a[pos]]++;
pos++;
}
//当出现重复数字
--pre[a[i]];
len[i] = pos - i; //表示从下标i开始最多有几个不重复的数
//cout << len[i] << ' ';
}
//cout << endl;
bool ans = false;
REP(i, 1, min(k, len[1] + 1) + 1) { //枚举起点,起点要小于等于 k 与 第一个数的无重复序列的长度+1(也就是起点前面是一个不完整的排列)的最小值
bool flag2 = true;
//cout << "i = " << i << endl;
for (int j = i; j <= n; j += k) { //从起点开始往后跳
if (n - j + 1 <= len[j]) // j到n是个部分排列也是合法的
continue;
else if (
len[j] !=
k) { //从起点开始k个数都应该是一个排列,也就是下标从j开始需要有k个不重复的数
flag2 = false;
break;
}
}
if (flag2) {
ans = true;
break;
}
}
if (ans)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}

浙公网安备 33010602011771号