2024萌新联赛1

萌新联赛补题

2024 河南萌新联赛 1


A 造数

给定整数 $n$,操作 1:$+1$,操作 2:$+2$,操作 3:$\times 2$,多少次将 $0$ 转化到 $n$

逆向思维,把 $n$ 化为 $0$ 即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <bits/stdc++.h>
using namespace std;

int main(){
    int n,cnt=0;
    cin>>n;
    while(n){
        if(n&1)n--,cnt++;
        else if(n>2)cnt++,n/=2;
        else cnt++,n-=2;
    }
    cout<<cnt<<endl;
}

H 两难抉择

长度为 $n$ 的数组 $a$,两种操作选一个进行一次或不操作。

显然将数组最大值 $\times n$ 后答案最大

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
    int n;
    cin>>n;
    vector<int>a(n);
    for(int i=0;i<n;i++)cin>>a[i];
    sort(a.begin(),a.end());
    int sum=0;
    for(int i=0;i<n;i++){
        sum+=a[i];
    }
    sum=max(sum+n,sum+(n-1)*a[n-1]);
    cout<<sum<<endl;
}

K 图上计数

构造的两块联通块即为最接近 $n/2$ 的两块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <bits/stdc++.h>
using namespace std;
#define int long long

int n,m;

signed main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
    }
    if(n<=1){
        cout<<"0\n";
        return 0;
    }
    cout<<(long long)n/2*(n-n/2)<<endl;
}

I 除法移位

$a$ 中最大值位于第一位时即是答案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <bits/stdc++.h>
using namespace std;
int main(){
    int n,t;
    cin>>n>>t;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int mx=0,ans=0;
    for(int i=1;i<=min(t,n);i++){
        if(a[n-i+1]>mx){
            mx=a[n-i+1];
            ans=i%n;
        }
    }
    cout<<ans<<endl;
}

F 两难抉择新编

与 H 类似,但是操作范围随 $i$ 改变而改变 $O(n^{3/2})$ 暴力过

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <bits/stdc++.h>
using namespace std;
#define int long long

signed main() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    int sum = 0, ans = 0;

    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) sum ^= a[i];
    ans = sum;

    for (int i = 1; i <= n; i++) {
        for (int x = 1; x <= n / i; x++) {
            int t1 = sum ^ a[i] ^ (a[i] + x);
            int t2 = sum ^ a[i] ^ (a[i] * x);
            ans = max(ans, max(t1, t2));
        }
    }

    cout << ans << endl;
    return 0;
}

G 旅途的终点

反悔贪心,前 $k$ 个直接存入 set,后续的小于 set 内第一个元素就替换,否则就正常进行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <bits/stdc++.h>
using namespace std;
#define ll __int128

int main(){
    long long n,m,k;
    cin>>n>>m>>k;
    vector<long long>a(n+1);
    for(int i=1;i<=n;i++)cin>>a[i];
    multiset<ll>s;
    for(int i=1;i<=n;i++){
        s.insert(a[i]);
        if(s.size()>k){
            m-=*s.begin();
            if(m<=0){
                cout<<i-1<<endl;
                return 0;
            }
            s.erase(s.begin());
        }
    }
    cout<<n<<endl;
    return 0;
}

B 爱探险的朵拉

图中可能有环,那么就是要找包含环的最长链,或是无环的最长链

记录每个点的入度,如果某个点的入度为 $0$,他们不会构成环,即可作为链起点,再依次对入度为 $0$ 的点操作,找出他们能构成最长的链有多长。

之后再以每个点为起点找答案,如果前面的过程标记过则跳过,没标记过说明这是环上点,用 dfs 找这个环加上前链有多长,并更新答案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;

int a[N],dis[N],cnt[N];
bool vis[N];
deque<int>q;

int dfs(int x){
    int sum=0,mx=0;
    for(int i=x;;i=a[i]){
        if(vis[i])break;
        vis[i]=1;
        ++sum;
        mx=max(mx,dis[i]);
    }
    return mx+sum;
}

int main(){
    int n,ans=0;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        cnt[a[i]]++;
    }
    for(int i=1;i<=n;i++)
        if(!cnt[i])q.push_back(i);
    while(!q.empty()){
        int x=q.front();
        q.pop_front();
        vis[x]=1;
        dis[a[x]]=max(dis[a[x]],dis[x]+1);
        --cnt[a[x]];
        if(!cnt[a[x]])q.push_back(a[x]);
    }
    for(int i=1;i<=n;i++){
        if(vis[i])continue;
        int tmp=dfs(i);
        ans=max(ans,tmp);
    }
    cout<<ans<<endl;
}

C 有大家喜欢的零食吗

二分图匹配板子,之后学了补


D 小蓝的二进制询问

显然是前缀和,那么重点就是如何计算前 $x$ 个数的 $1$ 的个数

从最低位看起,只有 $0$,$1$,二者循环,再往上 $1$ 位,仍然为 $0$,$1$ 循环,显然每一位上的循环都是一样的,我们对每一位能出现的 $1$ 进行计算,当前位数为 $k$ 时,这一位上就会有 $2^k$ 个 $1$ 和 $2^k$ 个 $0$。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 998244353;

ll sum(ll x,int y){ 
    if(x==0) return 0;
    ll s=1LL<<y;
    ll cnt=x/s;
    ll ans=cnt*s/2;
    ll d=cnt*s+(1LL<<(y-1));
    ll dd=x-d+1;
    if(dd>0) ans+=dd;
    return ans;
}

int main(){
    int t;
    cin>>t;
    while(t--){
        ll ans=0,l,r;
        cin>>l>>r;
        for(int i=61;i>0;i--){
            ll p=(sum(r,i)%MOD-sum(l-1,i)%MOD+MOD)%MOD;
            ans=(ans+p)%MOD;
        }
        cout<<ans<<endl;
    }
}

J 最大矩阵匹配

将矩阵上下翻转后,变为固定左上一个点,向其他三个方向拓展的问题,用二维前缀和辅助判断三个点是否都为 $1$,来实现 DP 状态转移

Licensed under CC BY-NC-SA 4.0
发表了95篇文章 · 总计15万2千字
永远相信美好的事情即将发生。
使用 Hugo 构建
主题 StackJimmy 设计