2020牛客寒假算法基础集训营1

2020牛客寒假算法基础集训营1

题号 标题 已通过代码 题解 讨论
A honoka和格点三角形 点击查看 进入题解 进入讨论
B kotori和bangdream 点击查看 进入题解 进入讨论
C umi和弓道 点击查看 进入题解 进入讨论
D hanayo和米饭 点击查看 进入题解 进入讨论
E rin和快速迭代 点击查看 进入题解 进入讨论
F maki和tree 点击查看 进入题解 进入讨论
G eli和字符串 点击查看 进入题解 进入讨论
H nozomi和字符串 点击查看 进入题解 进入讨论
I nico和niconiconi 点击查看 进入题解 进入讨论

E

\[O(\sqrt{n} )复杂度处理每一次迭代就行。是一道披着假数论的模拟 \]

每个数字分解质因数

计算x的素因子个数 j,向下模拟

12 = 1 2 3 4 6 12

6 = 1 2 3 6

4 = 1 2 4

3 = 1 3

分解到最后只有两个因子 即为答案

/*************************************************************************
	> File Name: e.cpp
	> Author: 
	> Mail: 
	> Created Time: 二  2/ 4 13:21:35 2020
 ************************************************************************/

#include<bits/stdc++.h>
using namespace std;
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;


ll sovle(ll n){
    ll i = 0,j = 0;
    for(i = 1;i * i < n; i++){
        if(n % i == 0){
            j += 2;
        }
    }
    if(i * i == n)j++; //f(3) = 1 // 1 * 1 = 1
    return j;
}

int main(int argc, char *argv[]) {
    SIS;
    ll n;
    cin >> n;
    ll sum = 0;
    while(n != 2){
        sum++;
        n = sovle(n);
    }
    cout << sum << endl;
    return 0;
}

F

题目要求任意取两点,只经过一个黑点的取法有多少种

  • 两个端点都是白点
  • 其中一个端点是黑点

预处理将每个白点联通块上的白点个数统计出来,这样我们知道,每个黑点连接了多少个白点

假设某黑点连接了k个白点,第i个白点的权值为f(i)

G

单独处理每种字符找k个的长度(双指针),求最小值

至少包含k个相同的字母, 那么代表肯定会有相同字母出现,但是我们并不知道这些字母最短的长度是多少,所以我们使用双指针来求得最短长度

如何处理呢,我们将每种字符的数量存入数组,同时遍历字符串;

在遍历的过程中,会出现当前字符的数量 == k,这时,我们就可以移动左指针,同时排除前面字符的干扰

什么意思呢,拿样例举例:

k = 2

abeba 我们得到的最短长度是3,假设为abecd...这样,我们可以知道,最短距离一定出现在 d字符的后面(abecdd.....),那么d字符前面的所有字符与后面相同字符串组成的长度一定大于 (abecdd..)这样组成的最短长度

假设我们在代码中不减去记录该数量的字符,我们会得到一个错误的解答

例如abced......dd

那么我们枚举到第三个d 的时候,我们发现b[’d'] 的值永远大于k 我们也无法枚举到最短长度的字符串. 我们只需要k个即可,不需要大于k的

/*************************************************************************
	> File Name: g.cpp
	> Author: 
	> Mail: 
	> Created Time: 二  2/ 4 13:37:07 2020
 ************************************************************************/

#include<bits/stdc++.h>
using namespace std;
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;

int num = 0,tmplen;
int minx = 0x3f3f3f3f;
string s;
int ans = minx;
int b[26];
int main(int argc, char *argv[]) {
    SIS;
    int n;
    int m;
    cin >> n >> m;
    cin >> s;
    int r,l;
    for( r = 0; r < n; r++){
        int t = s[r] - 'a';
        ++b[t]; // 记录字母
        if(b[t] == m) // 如果当前字母数量 == 我们需要的
        {
            while(l < r && s[l] != s[r])--b[s[l] - 'a'],++l;
        ans = min(ans, r - l + 1);
        --b[s[l] - 'a'];
        ++l;
        }
    }
    if(ans == minx){
        ans = -1;
    }

    cout << ans << endl;

    return 0;
}

H

两种方法:

  • 第一种

全1变0 或者 全0变1, 分别处理两种操作,对于1变0,可以分别统计

  • 1的前缀1,后缀1的位置(第一个1的前缀1的位置为0,最后一个1的位置为n + 1
  • k次操作,即变换连续k个1,最终的字符串长度就是第i个1的前缀1,到第i + k个后缀1之间到距离
#include<bits/stdc++.h>
using namespace std;
string s;
vector<int>v0,v1;       //v0存字符'0'的坐标位置,v1存字符'1'的坐标位置
int main(){
 
	int n,k,i,j;
	cin>>n>>k;
	cin>>s;
	v0.push_back(-1);
	v1.push_back(-1);
	for(i=0;i<n;i++){
		if(s[i]=='0')v0.push_back(i);
		else v1.push_back(i);
	}
	v0.push_back(n);
	v1.push_back(n);
	int ma=0;
	if(v0.size()-2<=k)ma=n;
	else{
		for(i=1,j=k;j<v0.size()-1;i++,j++){
			ma=max(ma,v0[j+1]-v0[i-1]-1);
			cout << (v0[j+1]-v0[i-1]-1) << endl;
		}
	}
	if(v1.size()-2<=k)ma=n;
	else{
		for(i=1,j=k;j<v1.size()-1;i++,j++){
			ma=max(ma,v1[j+1]-v1[i-1]-1);
		}
	}
	cout<<ma;
}
/*************************************************************************
    > File Name: test.cpp
    > Author:
    > Mail:
    > Created Time: 二  2/ 4 17:37:45 2020
 ************************************************************************/
#include <iostream>
#include <vector>
#include <string>
using namespace std;
  
int main()
{
    int n,m;
    cin>>n>>m;
    string str;
    cin>>str;
    vector<int> Hash(2,0);
    int res = 0, maxNum = 0;
    for(int i=0,j=0;j<str.size();j++){
        Hash[str[j]-'0']++;
        maxNum = max(maxNum, Hash[str[j]-'0']);
        while(j-i+1-maxNum>m)
            Hash[str[i++]-'0']--;
        res = max(res,j-i+1);
    }
    cout<<res<<endl;
}

I

转移方程

![image-20200204210446153](/Users/staryui/Library/Application Support/typora-user-images/image-20200204210446153.png)

#include<bits/stdc++.h>
using namespace std;
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 300005;
ll dp[maxn] = {0};
#define max(x, y)  (x) > (y) ? (x) : (y)

string a;
int main(int argc, char *argv[]) {
	SIS;
	
	  ll i,n,x,y,z;
		cin>>n>>x>>y>>z;
		cin>>a;
		for(i=0;i<n;i++){
			if(i>0)dp[i]=dp[i-1];
				if(i>=3&&a[i-3]=='n'&&a[i-2]=='i'&&a[i-1]=='c'&&a[i]=='o')
				dp[i]=max(dp[i],dp[i-3]+x);
			if(i>=5&&a[i-5]=='n'&&a[i-4]=='i'&&a[i-3]=='c'&&a[i-2]=='o'&&a[i-1]=='n'&&a[i]=='i')
				dp[i]=max(dp[i],dp[i-5]+y);
			if(i>=9&&a[i-9]=='n'&&a[i-8]=='i'&&a[i-7]=='c'&&a[i-6]=='o'&&a[i-5]=='n'&&a[i-4]=='i'&&a[i-3]=='c'&&a[i-2]=='o'&&a[i-1]=='n'&&a[i]=='i')
				dp[i]=max(dp[i],dp[i-9]+z);
		}
	cout << dp[n - 1] << endl;
	
	
	return 0;
}
posted @ 2020-02-24 15:48  跑快快  阅读(433)  评论(0)    收藏  举报