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;
}
posted @ 2020-08-09 22:09  cugbacm03  阅读(131)  评论(0)    收藏  举报