河南萌新联赛2024第(一)场

反思:强调,一定要把题看清楚了再写,真的会浪费很多时间,比如B,看到的第一眼还以为是前几天补过的题目,其实不是(可能会有很多环);一定要把所有题都尽量过一遍,就比如说c,就前几天才补过的题,不写好可惜;敢于暴力,勇于暴力,请多尝试(无语,该思考的时候不思考,不该想的时候想多了)

阶段一

两难抉择新编

思路:暴力,不太会算时间复杂度

代码:


int main() {
    int n;
    cin >> n;
    long long sum = 0;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
    {
cin >> a[i];
sum ^= a[i]; }
    long long ans = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n / i; j++)
        {
            ans = max(ans, sum ^ a[i] ^ (a[i] + j));
            ans = max(ans, sum ^ a[i] ^ (1ll * a[i] * j));
        }
    }
    cout << ans << '\n';
    return 0;
}

阶段二

有大家喜欢的零食吗

思路:板子题,前几天补过,但是因为看这个题看的有点晚,所以没写,再写了一遍匈牙利算法求二分图的最大匹配

再强调一遍,这里没有我喜欢的零食

正确代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=110,M=2e5+10;
int n;
int connect[510][510];
int p[510];
int cp[510];
bool check(int x){
    for (int j=1; j<=n; j++){
        if (connect[x][j]==1 && p[j]==0){
            p[j]=1;//记录搜索状态
            if (cp[j]==0|| check(cp[j])){
                cp[j]=x;
                return true;
            }
        }
    }
    return false;
}
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++){
        int k;
        cin>>k;
        int tt=0;
        while(tt<k){
            int x;
            cin>>x;
            connect[i][x]=1;
            tt++;
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        memset(p,0,sizeof p);
        if(check(i)) ans++;
    }
    if(ans==n) cout<<"Yes"<<endl;
    else {cout<<"No"<<endl;cout<<n-ans<<endl;}

}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

d小蓝的二进制询问

题解:

要求区间[l, r]的1的个数,显然我们可以用前缀和去计算,即区间[1, r]的个数减去区间[1, l − 1] 的个数作为答案。

下面考虑如何计算区间[1, r]的个数:

我们按位考虑,从最低位开始,显然最低位上是01 01 01循环,也就是两种情况,我们在此基础 上去考虑下一位,只看当前位的话仍然只有01两种情况,但是当我们结合上一位,一个0就是对 应上一位的所有情况,1同理,那么这一位就是0 0 1 1,以此类推,设当前位是第k位,那在当前 位上循环节就是2k+1 (2k个0和2k个1)每一位累加即可。

代码:

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f3f
using namespace std;
using ll = long long;
const int N = 4e5 + 7;
const int mod = 998244353;
ll f(ll x, ll k)
{
    ll y = 1ll << (k + 1);
    ll ok = y / 2;
    x++;
    ll res=x/y*ok;// 循环节内部分 ll r = x % y;
    ll r=x%y;
    r -= ok;
    if (r > 0)
        res += r; // 计算循环节多余部分 return res;
    return res;
}
void solve()
{
    ll l, r;
    cin >> l >> r;
    ll ans = 0;
    for (ll i = 61; i >= 0; i--)
    {
        ll p = (f(r, i) % mod - f(l - 1, i) % mod + mod) % mod;
        ans = (ans + p) % mod;
    }
    cout << ans << endl;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin>>t;
    while (t--) {
        solve();
    }
    return 0;
}

g路途的终点

思路:1.将每一座城市的伤害以及他的序号放入vector中排序,以便找到在前i个中伤害最大的几个城市,从后往前遍历,用神力抵消他们的伤害,用前缀和记录前i个城市的伤害在前i个中伤害最大的几个城市,减去可以抵消的最大伤害,如果最后小于等于0,就往前一个城市推(但是最后案例过了85%,没改出来)

错误代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll __int128//ll的前缀和数据范围很大,所以用int128维护
#define PII pair<int,int>
int n,m,k;
bool cmp(PII x,PII y){
    if(x.first==y.first) return x.second>=y.second;
    return x.first>y.first;
}
void solve() {
    cin>>n>>m>>k;
    int a[n+10];
    int b[n+10];//最好开成全局数组b[200010]
    memset(b,0,sizeof b);
    vector<PII>c;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
        b[i]=b[i-1]+a[i];
        c.push_back({a[i],i});
    }
    sort(c.begin(),c.end(),cmp);
    for(int i=n;i>=1;i--){
        int tt=0;
        int p=0;
        int sum2=0;
        while(c.size()-1>=p&&tt!=k){
            if(c[p].second<=i){
                sum2+=c[p].first;
                tt++;
            }
            p++;
        }
        if(m>b[i]-sum2) {
            cout<<i<<endl;
            return ;
        }
    }
    cout<<0<<endl;
    return;
 
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
//    cin>>t;
    while (t--) {
        solve();
    }
    return 0;
}

正解:

对于前 k 个国家,我们直接先选择消耗神力,从第 k + 1 个国家开始我们就从我们选择消耗神力 的 k 个国家中选择出一个在不消耗神力的前提下,需要消耗的生命力最小的国家,并假设该国家 为 i ,需要消耗的生命力为 ai 。同时我们设我们当前所在的国家为 j ,需要消耗的生命力为 aj 。 若 ai > aj ,则我们选择在第 j 个国家消耗生命力,仍在第 i 个国家消耗神力,这样可以保证我 们的生命力消耗的最小;反之,则我们选择在第 i 个国家消耗生命力,在第 j 个国家消耗神力, 以此来逐渐更新,保证答案最大。这个过程类似于一个反悔贪心的过程。最后当发现无法畅游某 一个国家或可以旅行完全部国家时就代表找到答案了。

注意:本题中 ∑n ai 的值会超出 long long 类型的数据范围,因为 m 的取值范围没有超出 i=1

long long 类型 故若找到答案之后立刻结束则可以保证不会超出 long long 的数据范围。当然, 若使用 __int128 类型,则不必担心这个问题。

因为本题只遍历一遍,时间复杂度为 O(n),而优先队列的每次pop和push的时间复杂度为 O(logn) ,所以本题的时间复杂度为O(nlogn)。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值