A. Dalton the Teacher

题意:懂得都懂

思路:直接记录有几个不高兴的,给他们互相换换即可

diamond:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
int fa[100005];
int n,m;
void solve(){
    int ans=0;
    int n;
    cin>>n;
    vector<int >g(n+1);
    for (int i = 1; i <=n ; ++i) {
        cin>>g[i];
    }
    int p=0;
    for (int i = 1; i <=n ; ++i) {
        if(g[i]==i){
            p++;
        }
    }
    ans+=max((p+1)/2,(int)0);
    cout<<ans<<'\n';

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

B. Longest Divisors Interval

题意:问1-n中,最长的n的因子的连续区间的长度为多少

思路:结论表明最长的区间必然是从1开始的区间,假设我们找到的1到5这个区间都是因子,如果存在一个区间的长度是大于这个区间的话,比如9-14,那么我们可以发现其中的长度是等于6的,那么证明其中一定存在6的因子,那么其实就可以发现我们前面那个区间的长度又可以扩大了,1-6,依次类推,那么我们就可以从1枚举,找到第一个不是因子的数i,i-1为答案

diamond:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define  ll long long
const int mod=1e9+7;
int fa[100005];
int n,m;
//int find(int x){
// if(fa[x]!=x){
// fa[x]=find(fa[x]);
// }
// return fa[x];
//}
//void merge(int x,int y){
// int dx=find(x),dy=find(y);
// fa[dy]=dx;
//}

void solve() {
    unordered_map<ll, ll> has;
    int x;
    cin >> x;
    int ans=0;
    int p=0;
    for (int i = 1; i <=500 ; ++i) {
        if(x%i==0){
            p++;
        }
        else{
            ans=max(ans,p);
            p=0;
        }
    }
    ans=max(p,ans);
    cout<<ans<<'\n';
//    for (int i = 2; i <= x / i; ++i) {
//        while (x % i == 0) {
//            has[i]++;
//            x /= i;
//        }
//    }
//    if (x > 1)
//        has[x]++;
//    ll cnt = 1;
//    for (auto p: has) {
//        cnt = cnt * (p.second + 1) % mod;
//        cout<<p.first<<' '<<p.second<<endl;
//    }
//    set<int>st;
//    for (auto i:has) {
//
//    }

//    cout << cnt;

}
signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while (t--){
        solve();
    }
}
/* 2 2
 * ld
 * ul
 * 1 1
 * 1 1
 *
 */

C1. Dual (Easy Version)and(C2)

题意:给一个数组,每次操作我们可以把一个数加到另一个数上,可以加本身,问我们怎么操作才能使数组是递增的

思路:直接按照Hard版本的讲,我们可以看到题目给的次数是$k<=31$次,如果我们数组全部为正或为负,那么我们最多19次求一遍前缀和或者后缀和即可,那么如果存在不同的,我们其他的12次就可以用来变负为正或者变正为负的操作,假设我们得到$abs(max)>=abs(min)$,正的绝对值>=负的绝对值,我们首先考虑变负为正,我们最多变12次,那么当负的个数<=12,我们就可以直接操作,假设>12,那么考虑把正的变为负,因为正的只有<=7个,我们先把$abs(min)$变为大于等于$abs(max)$,最差情况,min=-1,我们对他进行加自己的操作,那么-1 -2 -4 -8 -16 -32,最差进行5次操作即可>=正的最大值,最后把正的变为负,再进行后缀和操作,刚好是5+7+19=31次操作,如果$abs(max)<abs(min)$,反过来操作即可

diamond:

#include<bits/stdc++.h>
using namespace std;
//#define int long long
//#define  ll long long
const int mod=1e9+7;
int fa[100005];
int n,m;
#define endl '\n'
void solve() {
    cin>>n;
    vector<int >g(n+1);
    vector<pair<int,int>>ans;
    int ma=-99,mi=99;
    int idxma=0,idxmi;
    int zheng=0,fu=0;
    for (int i = 1; i <=n ; ++i) {
        cin>>g[i];
        if(g[i]>=0)zheng++;
        else
            fu++;
        if(ma<g[i]) {
            ma = max(ma, g[i]);
            idxma=i;
        }
        if(mi>g[i]) {
            mi = min(mi, g[i]);
            idxmi=i;
        }
    }
    if(mi>=0){
        cout<<n-1<<endl;
        for (int i = 1; i <=n-1 ; ++i) {
            cout<<i+1<<' '<<i<<endl;
        }
        return;
    }
    if(ma<=0){
        cout<<n-1<<endl;
        for (int i = n; i >1 ; --i) {
            cout<<i-1<<' '<<i<<endl;
        }
        cout<<endl;
        return;
    }
    if(abs(ma)>=abs(mi)){
        if(fu<=12){
            for (int i = 1; i <=n ; ++i) {
                if(g[i]<0){
//                    cout<<i<<' '<<idxma<<endl;
                    ans.push_back({i,idxma});
                }
            }
            for (int i = 1; i <=n-1 ; ++i) {
                ans.push_back({i+1,i});
            }
        }
        else{
            for (int i = 0; i <5 ; ++i) {
                ans.push_back({idxmi,idxmi});
            }
            for (int i = 1; i <=n ; ++i) {
                if(g[i]>=0){
                    ans.push_back({i,idxmi});
                }
            }
            for (int i = n; i >1 ; --i) {
//                cout<<i-1<<' '<<i<<endl;
                    ans.push_back({i-1,i});
            }
        }
    }
    else {
        if(zheng<=12){
            for (int i = 1; i <=n ; ++i) {
                if(g[i]>=0){
//                    cout<<i<<' '<<idxma<<endl;
                    ans.push_back({i,idxmi});
                }
            }
            for (int i = n; i >1 ; --i) {
//                cout<<i-1<<' '<<i<<endl;
                ans.push_back({i-1,i});
            }
        }
        else{
            for (int i = 0; i <5 ; ++i) {
                ans.push_back({idxma,idxma});
            }
            for (int i = 1; i <=n ; ++i) {
                if(g[i]<0){
                    ans.push_back({i,idxma});
                }
            }
            for (int i = 1; i <=n-1 ; ++i) {
                ans.push_back({i+1,i});
            }
        }
    }
    cout<<ans.size()<<endl;
    for (auto i:ans) {
            cout<<i.first<<' '<<i.second<<endl;
    }

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

D. Earn or Unlock

题意:给n张牌,每张牌的价值是$ai$,刚开始除了第一张,每一张牌都上锁了,在开锁的牌里选一张,进行操作,操作有两种,第一种是解锁V个没有解锁的牌,从上往下依次,第二种操作是ans+=V;问答案的最大值是多少

思路:我们可以发现,解锁的牌数和价值是等价的,比如 $2 4 5 0 1$,当你解锁3张牌时,你的答案就是$2+4+5-(2-0)=9$,这就是最大,假设用掉了x张牌,就说明x张牌都是解锁的花了(x-1)的点数去解锁,剩下的就是贡献,即是$ans=sum-(x-1)$(第一张牌不用解锁),sum为前缀和,我们的做法是去枚举ans取最大即可,即是枚举x

:即是用DP求每一张牌的状态x,由于DP是n^2,所有我们用bitset表示状态,例如2 4 5 0 1,bt状态为1 0 0 0 0,代表刚开始只有第一张牌是解锁的,那么我们就可以操作2求一遍ans,然后我们进行操作1,那么我们的bt状态就变成了0 0 1 0 0 ,1前面的都是解锁了的,当我们遍历到idx=1时,我们发现,这时不用更新ans,因为你如果对idx=1的位置进行操作2,其实在idx=2的位置进行操作2时就已经包括了,在3时更新明显更优,那么在idx=1时由于bt[1]=0我们只有一种操作,就是对他进行操作1,那么我们的bt就变成了0 0 1 0 0 0 1,然后遍历到2时发现,idx=1,那么我们对他进行操作2,更新ans,然后进行操作1,因为对idx=1时,他可以不进行操作1,也可以进行操作1,那么idx=2进行操作1时,就会产生两种情况,bt就变成了0 0 0 0 0 0 1 1 0 0 1,变成了这种情况,最后两个1即是新产生的两种情况,依次类推,每一个1都代表了一种独立的情况,这些1的位置最多是在2 * n-1的位置,在大于n时,其实就代表了最后解锁时你剩余的牌数小于这个值V,这样也符合题意,我们得到的新的1会溢出,遍历到1时,我们更新,是正确的。

diamond:

#include<iostream>
#include<string>
#include<cstdio>
#include<bitset>
using namespace std;
#define debug 0
const int maxn = 200010;
#define ll long long

int n;
int a[maxn];
//ll dp[maxn];
bitset<maxn> dp;

void solve() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
        scanf("%d", &a[i]);
    }
    n <<= 1; // 2倍 

    ll ans = 0, sum = 0;
    dp[0] = 1;
    for (int i = 0; i  < n; ++i) {
        dp |= (dp << a[i]);
        sum += a[i];
        if (dp[i] == 1) {
            ans = max(ans, sum - i);
            dp[i] = 0;
        }
    }
    printf("%lld\n", ans);

}
int main() {
    int t = 1;
//  scanf("%d", &t);
    while (t--) {
        solve();
    }
}
posted on 2023-08-05 14:49  IR101  阅读(8)  评论(0编辑  收藏  举报  来源