首页 > 其他分享 >牛客周赛ROUND38

牛客周赛ROUND38

时间:2024-03-30 21:33:21浏览次数:15  
标签:周赛 int sum ROUND38 牛客 vector ans 指针 逆序

E题

链接:https://ac.nowcoder.com/acm/contest/78292/E
来源:牛客网

小苯非常喜欢等比数列。有一天他得到了一个长为 \(n\) 的数组 \(a\),他想从里面选一些数字使得被选中的数字构成一个等比数列,请问他最多可以选择多少个数字呢

输入包含两行。

第一行一个正整数 \(n\ (1\leq n \leq 2 \times 10^5)\),表示数组 \(a\) 的长度。
第二行 \(n\) 个正整数 \(a_i \ (1 \leq a_i \leq 2 \times 10^5)\),表示数组 \(a\) 的元素。

solution:比较经典的不同范围不同做法,由于公比过大的时候会乘几次就结束,所以我们对此暴力。对于公比小的部分进行dp递推

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int N = 2e5 + 5;
inline void solve()
{
    int n; cin >> n;
    vector<int> a(n + 5);
    vector<int> st(N, 0);
    for(int i=1; i<=n; i++)
        cin >> a[i], st[a[i]] = 1;
    sort(a.begin()+1, a.begin()+1+n);
    int ans = 1;
    vector<vector<int>> dp(N, vector<int>(101, 0));//dp[i][j]:以a[i]结尾的, 公比为j的等比数列的最大长度
    
    //100n
    for(int i=1; i<=n; i++) {
        dp[a[i]][1] ++;
        ans = max(ans, dp[a[i]][1]);
        for(int j=2; j<=100; j++) {//公比
            if(a[i] % j == 0) {
                if(st[a[i] / j]) dp[a[i]][j] = 2;//如果只选了这两个
                dp[a[i]][j] = max(dp[a[i]][j], dp[a[i] / j][j] + 1);
                ans = max(ans, dp[a[i]][j]);
            }
        }
    }
    //分块
    for(ll i=100; i<=2e5; i++) {//公比>100, 至多1~3次
    //实际复杂度只有O(n)
        for(ll j=1; j*i<=2e5; j++) {//首项
            if(!st[j]) continue;
            if(!st[j*i]) {
            	//考虑有没有第二项
                ans = max(ans, 1); continue;
            } 
            if(j*i*i > 2e5 || !st[j*i*i]) {
            	//考虑有没有第三项
                ans = max(ans, 2); continue;
            }
            ans = max(ans, 3);
            break;
        }
    }
    cout << ans << endl;
}

G:双指针维护逆序对

题目

链接:https://ac.nowcoder.com/acm/contest/78292/G
来源:牛客网

小红有一个长度为 \(n\) 的数组 \(a\),他想从 \(a\) 中删除一段区间,但又要使得剩余的部分拼起来组成的新数组满足:逆序对个数不少于 \(k\)。

她想知道有多少种删除方案,请你帮帮她吧。
注:空数组逆序对数量为0。

solution:首先本题就是双指针,只不过维护的是逆序对,比常规双指针增加难度

我们考虑固定R。对于L,由于是删除区间,左指针右移表示删除区间缩小,逆序对数量增加。
所以我们对于每一个r需要找到极限l,l满足恰好>=k。考虑每次移动l都增加了多少逆序对,我们计算具体贡献

  1. 增加的是R后面比a[l]小的元素,
  2. 还有就是L前面a[l]大的
  • 对于2的贡献我们只需要移动l的时候在线维护
  • 对于1的贡献由于指针是从左往右移动,所以我们只有提前维护后缀的值域树状数组,跟着r移动的时候在线删除维护,这样才可以
  • 每次删除右端点的元素减去贡献计算同理
int n, m;
int a[N];
//首先本题就是双指针,只不过维护的是逆序对,比常规双指针增加难度
//我们考虑固定R。对于L,由于是删除区间,左指针右移表示删除区间
//缩小,逆序对数量增加。
//所以我们对于每一个r需要找到极限l,l满足恰好>=k。
//每次移动l都增加了多少逆序对,我们计算具体贡献

//1增加的是R后面比a[l]小的元素,
//2.还有就是L前面a[l]大的


//对于2的贡献我们只需要移动l的时候在线维护
//对于1的贡献由于指针是从左往右移动,所以我们只有提前维护后缀的
//值域树状数组,跟着r移动的时候在线删除维护,这样才可以
template <typename T>
struct Fenwick {
    int n;
    std::vector<T> a;
    
    Fenwick(int n_ = 0) {
        init(n_);
    }
    
    void init(int n_) {
        n = n_;
        a.assign(n, T{});
/*
T{}是一种初始化T类型对象的方式,它使用了花括号初始化列表进行数值初始化。
对于大多数内置数据类型(如整数、浮点数),这将初始化为0。
*/

    }
    
    void add(int x, const T &v) {
        for (int i = x; i <=n-1; i += i & -i) {
            a[i] = a[i] + v;
        }
    }
    
    T sum(int x) {
        T ans{};
        for (int i = x; i > 0; i -= i & -i) {
            ans = ans + a[i];
        }
        return ans;
    }
    
    T rangeSum(int l, int r) {//要传入l-1
    //待优化:直接给个vector记录前缀和
        return sum(r) - sum(l);
    }
    
    int select(const T &k) {//寻找最后一个使得前缀和小于等于 k 的位置。
        int x = 0;
        T cur{};
        for (int i = 1 << std::__lg(n-1); i; i /= 2) {//GCC
            if (x + i <= n-1 && cur + a[x + i] <= k) {
                x += i;
                cur = cur + a[x];
            }
        }
        return x;
    }
};
void solve(){
	cin>>n;cin>>m;
	for(int i=1;i<=n;i++)cin>>a[i];
	Fenwick<int>suf(1e6+1),pre(1e6+1);
	int sum=0;
	for(int i=n;i>=1;i--){
		suf.add(a[i],1);
		sum+=suf.sum(a[i]-1);
		//suf.add(a[i],1);
	}
	int ans=0;
	if(sum>=m)ans++;
	for(int i=1,j=1;i<=n;i++){
		suf.add(a[i],-1);
		sum-=suf.sum(a[i]-1);
		sum-=pre.rangeSum(a[i],1000000);
		//suf.add(a[i],-1);
		while(j<=i&&sum<m){
			pre.add(a[j],1);
			sum+=suf.sum(a[j]-1);
			sum+=pre.rangeSum(a[j],1000000);
			//pre.add(a[j],1);
			j++;
		}
		ans+=i-j+1;
		
	}
	cout<<ans<<endl;
	
}

标签:周赛,int,sum,ROUND38,牛客,vector,ans,指针,逆序
From: https://www.cnblogs.com/mathiter/p/18106057

相关文章

  • 牛客月赛~~B显生之宙
    题目描述:白垩色的王子给了你一个由n个数组成的数列,并告诉你,你需要执行n-1次如下操作:选定一个数列中的数x,再选择数列中的至少一个其他数,然后让这些数都加上x,再将x移除出这个数列。经n-1次操作过后,数列中最后只会剩下一个数。白垩色的王子希望你告诉他,最后剩下的......
  • 牛客 [NOIP2001]数的划分
    https://ac.nowcoder.com/acm/problem/16695#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;typedefpair<int,int>PII;constLLMAXN=1e18,MINN=-MAXN,INF=0x3f3f3f3f;constLLN=200200,M=2020;LLn,k;LLans=0;voiddfs(intidx......
  • 牛客竞赛动态规划专题班数位dp例题
    题单A-0的个数这题算是一个思维题。我的做法是就是统计每一位的0有多少个。例如\(4032\)个位的零有\(403\)种十位的零有\(40*10\)种百位的零有\(3*100+33\)种,即千位去\([1,3]\)个位低两位取\([00,99]\),或者千位取\(4\)低两位取\([00,33]\)千位不能取零#include<......
  • Leetcode 第 126 场双周赛题解
    Leetcode第126场双周赛题解Leetcode第126场双周赛题解题目1:3079.求出加密整数的和思路代码复杂度分析题目2:3080.执行操作标记数组中的元素思路代码复杂度分析题目3:3081.替换字符串中的问号使分数最小思路代码复杂度分析题目4:3082.求出所有子序列的能量和思......
  • Leetcode 第 388 场周赛题解
    Leetcode第388场周赛题解Leetcode第388场周赛题解题目1:3074.重新分装苹果思路代码复杂度分析题目2:3075.幸福值最大化的选择方案思路代码复杂度分析题目3:3076.数组中的最短非公共子字符串思路代码复杂度分析题目4:3077.K个不相交子数组的最大能量值思路代码......
  • 小猴编程周赛C++ | 最小能力差
    学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!附上汇总贴:小猴编程C++|汇总-CSDN博客【题目描述】某校信竞社团有nnn......
  • 小猴编程周赛C++ | 卡牌顺序
    学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!附上汇总贴:小猴编程C++|汇总-CSDN博客【题目描述】小猴有nnn卡牌,编号......
  • 牛客编程题
    提示:文章文章目录前言一、背景二、2.12.2总结前言前期疑问:本文目标:一、背景最近二、2.1坐标移动https://www.nowcoder.com/practice/119bcca3befb405fbe58abe9c532eb29?tpId=37&tqId=21240&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2......
  • 力扣周赛382
    3019.按键变更的次数给你一个下标从 0 开始的字符串 s ,该字符串由用户输入。按键变更的定义是:使用与上次使用的按键不同的键。例如 s="ab" 表示按键变更一次,而 s="bBBb" 不存在按键变更。返回用户输入过程中按键变更的次数。注意:shift 或 capslock 等修饰......
  • 牛客周赛 Round 38做题笔记
    一.题目链接登录—专业IT笔试面试备考平台_牛客网牛客网是互联网求职神器,C++、Java、前端、产品、运营技能学习/备考/求职题库,在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨论经典试题,全面提升你的技术能力https://ac.nowcoder.com/acm/contest/78......