牛客小write月赛 40

A题

  • 思路
    分奇偶讨论。
    偶数个 1 1 1
    最后一个位置存在 1 1 1,则除了第一个和最后一个,每次消掉一个 1 1 1,需要两次。
    奇数个同理推导。
  • 代码
ll x;scanf("%lld",&x);
    bool flag = x%2;
    int cnt = 0;
    for (int i = 0 ;i <= 32 ;i ++) {
        if ((x>>i)&1 == 1) cnt ++;
    }
//     cout<<cnt<<endl;
    if (x == 4) {
        printf("3\n");return;
    }
    if (!cnt) {
        printf("0\n");return;
    }
    if (cnt & 1) {
        if (flag) {
            printf("%d\n",1+(cnt-1)*2);
        } else {
            printf("%d\n",3+(cnt-1)*2);
        }
    }
    else {
        if (flag) {
            printf("%d\n",2+(cnt-2)*2);
        } else {
            printf("%d\n",cnt*2);
        }
    }

B题

  • 题意
    在这里插入图片描述
  • 思路
    动态规划-区间 d p dp dp

区间 d p dp dp 部分:
f [ i ] [ j ] f[i][j] f[i][j] 表示当前走完的点中 i i i 为左端点, j j j 为右端点时获得的最高分,确定了 i , j i,j i,j 之后,可以确定当前走完了 j − i + 1 j-i+1 ji+1 步,并且当前停留在 i i i 或者 j j j 这个位置,那么可以得到递推方程
f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] + a [ i ] ∗ ( j − i + 1 ) , f [ i ] [ j − 1 ] + a [ j ] ∗ ( j − i + 1 ) ) f[i][j]=max(f[i-1][j]+a[i]*(j-i+1),f[i][j-1]+a[j]*(j-i+1)) f[i][j]=max(f[i1][j]+a[i](ji+1),f[i][j1]+a[j](ji+1))
因为要么走左边,要么走右边

实现:
第一层枚举走的步数
l e n = 1 − t o − n len=1 -to -n len=1ton
第二层枚举左端点 i i i
i = 1 − t o − n − l e n + 1 i=1 - to - n-len+1 i=1tonlen+1
此时可以确定右端点 j = i + l e n − 1 j=i+len-1 j=i+len1,然后正常递推方程
由于这是个环,有一个比较常见的处理技巧就是开 2 2 2 倍数组,
最后枚举左端点
i = 1 − t o − n i=1- to- n i=1ton
a n s = m a x ( a n s , f [ i ] [ i + n − 1 ] ) ans=max(ans,f[i][i+n-1]) ans=max(ans,f[i][i+n1])

  • 代码
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 2e4+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){

    cout<<s<<": "<<x<<endl;
}

#define PII pair<int,char>
ll a[N*2];
ll dp[N][N];
void solve()
{
	int n; cin>>n;
	for (int i = 1;i <= n;i ++) {
		cin>>a[i]; a[i+n] = a[i];
        dp[i][i] = a[i];
        dp[i+n][i+n] = a[i];
	}
// 	memset(dp,0,sizeof(dp));
    for (ll len = 2;len <= n;len ++) {
        for (ll i = 1;i + len -1 <= 2*n;i ++) {
            ll j = i + len - 1;
            dp[i][j] = max(dp[i+1][j] + a[i]*len,dp[i][j-1]+a[j]*len);
        }
    }
    ll ans = 0;
    for (int i = 1;i <= n;i ++) {
        ans = max(ans,dp[i][i+n-1]);
    }
    cout<<ans<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.txt", "r", stdin);
	freopen("aout.txt", "w", stdout);
#endif
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int t;
	// cin >> t;
	t = 1;
	while (t--)
		solve();
}

注: d p dp dp 记得初始化。

C题

  • 题意
    在这里插入图片描述
  • 思路

先预处理出 1   n 1~n 1 n 中对于每个数,其二进制形式中长度为 k k k 的子串有哪些,并转成十进制存储,此处是一个 n 2 n^2 n2的存储,然后 n 2 n^2 n2 枚举所有数对,对于任意一个数对 ( x , y ) (x,y) (x,y),我们需要判断是否匹配,可以直接枚举 x x x 中长度为 k k k 的子串所代表的的数字是否在 y y y 中出现过,若出现过则是匹配
这样处理的理论复杂度是 n 2 l o g n^2log n2log,并且,由于这个 l o g log log 特别小几乎可以忽略不计所以在实际运行中是跑的特别快的,如果写的比较优美,甚至可以两个 l o g log log 跑过去

  • 代码

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

int ka;
int f[MAXN][MAXN];
int ask(int x,int y)
{
    int p=0,q=0,s=x,t=y;
    while (s)    s>>=1,p++;
    while (t)    t>>=1,q++;
    if (p<ka||q<ka)    return 0;

    for (int i=0;i+ka-1<p;i++) {
        for (int j=0;j+ka-1<q;j++) {
            int now1=(x>>i),now2=(y>>j),cnt=0;
            for (int k=0;k<min(ka,min(q-j,p-i));k++)
                if ((now1&(1<<k))==(now2&(1<<k))){
                    cnt++;
                    if (cnt>=ka)  return 1;
                } else cnt=0;
        }
    }
    
    return 0;
}

int main(){
    int n,ans=0;
    cin>>n>>ka;
    for (int i=(1<<ka-1);i<=n;i++)
        for (int j=i+1;j<=n;j++){
            ans+=ask(i,j);
        }
    cout<<ans<<endl;
    return 0;
}

D题

  • 思路
    直接扫一遍,碰到重复的加个 1 1 1
  • 代码
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 3e5+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){

    cout<<s<<": "<<x<<endl;
}

#define PII pair<int,char>
PII a[N];
bool cmp (PII a, PII b){
	if (a.second == b.second) return a.first < b.first;
	return a.second < b.second;
}
void solve()
{
	string s;cin >> s;
	int ans = s.size();
	for (int i = 1;i < s.size();i ++) {
		if (s[i] == s[i-1]) {
			ans ++;
		}
 	}
	cout<<ans<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.txt", "r", stdin);
	freopen("aout.txt", "w", stdout);
#endif
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int t;
	cin >> t;
	while (t--)
		solve();
}



E题

  • 思路
    二分检验
  • 代码
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 3e5+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){

    cout<<s<<": "<<x<<endl;
}

#define PII pair<int,char>
int a[N];
void solve()
{
	int n,m;cin>>n>>m;
	map<int,int> jud;
	for (int i = 1;i <= n;i ++) {
		cin>>a[i]; jud[a[i]] ++;
	}
	if (jud.size() > m) {
		cout<<-1<<endl;return;
	}
	vector<int> vec;
	for (auto &xx:jud) {
		vec.push_back(xx.second);
	}
	sort(vec.begin(),vec.end());
//     cout<<vec[vec.size()-1]<<endl;
    int l = 1,r = n;
    while (l < r) {
        int mid = (l+r)>>1;
        int cnt = 0;
        for (int i = 0;i < vec.size() ;i ++) {
            cnt += vec[i]/mid;
            if (vec[i]%mid!=0) cnt ++;
        }
        if (cnt > m) {
            l = mid + 1;
        }
        else {
            r = mid; 
        }
    }
    cout<<l<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.txt", "r", stdin);
	freopen("aout.txt", "w", stdout);
#endif
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int t;
	// cin >> t;
	t = 1;
	while (t--)
		solve();
}



F题

  • 思路
    d p [ i ] [ j + k ] = d p [ i ] [ j ] + 1 dp[i][j+k] = dp[i][j]+1 dp[i][j+k]=dp[i][j]+1;
    k ∈ 1... a [ i ] ,     i f   a [ i ] > 0 k \in {1...a[i]}, ~~~if ~a[i]>0 k1...a[i],   if a[i]>0
  • 代码
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 3e5+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){

    cout<<s<<": "<<x<<endl;
}

#define PII pair<int,char>
int a[N];
int dp[N];
void solve()
{
	int n;cin>>n;
	for (int i = 1;i <= n;i ++) {
		cin>>a[i];
	}
	memset(dp,0x3f3f3f3f,sizeof(dp));
	dp[1] = 0;
	for (int i = 1;i <= n;i ++) {
		if (a[i] > 0) {
			for (int j = 2;j <= n;j ++) {
				if (j <= i + a[i]) {
					dp[j] = min(dp[j],dp[i] + 1);
				}
				else break;
			}
		}
	}
	if (dp[n] == 0x3f3f3f3f) {
		cout<<-1<<endl;
	} else {
		cout<<dp[n]<<endl;
	}

}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.txt", "r", stdin);
	freopen("aout.txt", "w", stdout);
#endif
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int t;
	// cin >> t;
	t = 1;
	while (t--)
		solve();
}

G题

  • 思路
    枚举每个位置,二分找到并算出 a [ i ] − p , a [ i ] + p a[i]-p,a[i]+p a[i]p,a[i]+p 区间长度。
  • 代码
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e6+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){

    cout<<s<<": "<<x<<endl;
}

#define PII pair<int,char>
int a[N];
void solve()
{
	int n,p;cin>>n>>p;
	for (int i = 1;i <= n;i ++) cin>>a[i];
	sort(a+1,a+1+n);
	int cnt = 0;
	for (int i = 1;i <= n;i ++) {
		int tcnt = 0;
		int l = lower_bound(a+1,a+1+n,a[i] - p) - a;
		int r = upper_bound(a+1,a+1+n,a[i] + p) - a;
		tcnt = (r-l);
		cnt = max(cnt,tcnt);
	}
	cout<<cnt<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.txt", "r", stdin);
	freopen("aout.txt", "w", stdout);
#endif
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int t;
	// cin >> t;
	t = 1;
	while (t--)
		solve();
}



H题

  • 题意
    在这里插入图片描述

  • 思路
    这题所有数据范围都是 1 e 6 1e6 1e6 以内的
    首先子集的 g c d = x gcd=x gcd=x,那么这个子集里所有数都必然是 x x x 的倍数
    反过来说如果子集里所有数都是 x x x 的倍数,那么这个子集 g c d gcd gcd 可能是 x x x 也可能是 x x x 的倍数
    所以思路就有了,对于每次询问 x x x,查询 x x x, 2 x 2x 2x, 3 x 3x 3x……有无出现过,有就强行 g c d gcd gcd,在这个过程中,如果 g c d = x gcd=x gcd=x 了,即可停止
    那么问题来了,如果每次操作都要一直查询,会不会导致复杂度变大,
    我们可以开个数组标记,如果已经询问过 x x x 了,直接输出对应答案,否则查询
    这样对于每个 x x x,都不会重复跑查询,那么他整个复杂度就是调和级数的复杂度,显然是可行的

  • 代码

#include <stdio.h>
#include <string.h>

const int N = 1000005;

int n, m;
bool cur[N], res[N];

int gcd(int x, int y) {
	while (y ^= x ^= y ^= x %= y);
	return x;
}

int main() {
	int task;scanf("%d", &task);
	while (task--) {
		scanf("%d%d", &n, &m);
		memset(cur + 1, false, n);
		memset(res + 1, false, n);
		for (int i = 1; i <= n; ++i) {
			int x;
			scanf("%d", &x);
			cur[x] = true;
		}
		for (int x = 1; x <= n; ++x) {
			int d = 0;
			for (int i = 1; i * x <= n; ++i) {
                if (i * x >= 1 && cur[i * x]) {
                    d = gcd(d, i);
                    if (d == 1) {
                    	//这样就保证了 gcd == x;
                        res[x] = true; break;
                    }
                }
            }
		}
		while (m--) {
			int x;
			scanf("%d", &x);
			puts(res[x] ? "YES" : "NO");
		}
	}
	return 0;
}

I题

  • 思路

全排列

  • 代码
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 3e5+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){

    cout<<s<<": "<<x<<endl;
}

#define PII pair<int,char>
int b[15];
int a[100];int cnt = 0;
void dfs(int cur,int n)//cur表示目前正在填的数,n表示总共要填的数 
{
    if(cur==n)//递归边界,说明填完了 
    {
		vector<int> vec(n+1);
        for(int i=0;i<n;i++)//一个一个的输出 
		{
            
			vec[a[i]] = i+1;
		}		
		for(int i = 1;i <= n;i ++) {
			if (vec[i] < vec[b[i]]) {
				return;
			}
		}
		cnt++;
		return;
    }
    for(int i=1;i<=n;i++)//把数字1-n填入 
    {
        int ok=1;
        for(int j=0;j<cur;j++) 
        {
            if(a[j]==i) ok=0;
        }
        if(ok==1)
        {
            a[cur]=i;
            dfs(cur+1,n);
        }
    }
}
void solve()
{
	int n;cin>>n;
	for (int i = 1;i <= n;i ++) {
		cin>>b[i];
	}
	dfs(0,n);
    cout<<cnt<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.txt", "r", stdin);
	freopen("aout.txt", "w", stdout);
#endif
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int t;
	// cin >> t;
	t = 1;
	while (t--)
		solve();
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的码泰君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值