2023牛客寒假训练营1补题

K

分析

思维题,先考虑100100100....这样一个序列能接受最多的1的情况
如果有多的1,就先从后面开始放
赛时是一样的思路,但是细节方面没处理好

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
vector<int> s;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
    }
inline void print(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
        putchar(x%10+'0');
    }
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin >> n >> m;
    int p = n - m;
    while(m || p){
        if(m) s.push_back(1),m--;
        if(p) s.push_back(0),p--;
        if(p) s.push_back(0),p--;
    }

    int ans = 0;
    for(int i=1;i<n-1;i++)
        if(s[i] + s[i-1] + s[i+1] >=2)
            ans++;
    
    cout << ans << endl;
    return 0;
}

D

分析

基本上算一眼结论题,四个区域分别讨论即可,赛时在纠结K,没有细看该题

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
    }
inline void print(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
        putchar(x%10+'0');
    }
void solve(){
    int x,y,xp,yp;
    cin >> x >> y >> xp >> yp;
    if(xp <= x && yp <= y){
        int sum = x * y;
        int maxx = 0;
        maxx = max(maxx,xp*yp);
        maxx = max(maxx,(y-yp)*xp);
        maxx = max(maxx,(x-xp)*(y-yp));
        maxx = max(maxx,(x-xp)*yp);
        double res = (double)maxx/(double)sum;
        cout << res << endl;
    }
    else{
        if(xp >= x && yp >= y){
            int sum1 = x * y;
            int sum2 = xp * yp;
            int jq = x*y;
            int m = sum1 + sum2 - jq;
            double res = (double)jq/(double)m;
            cout << res << endl;
        }
        else if(xp >= x && yp < y){
            int sum1 = x * y;
            int sum2 = xp * yp;
            int jq = x*yp;
            int m = sum1 + sum2 - jq;
            double res = (double)jq/(double)m;

            sum2 = xp*(y-yp);
            jq = x*(y-yp);
            m = sum1 + sum2 - jq;
            res = max(res,(double)jq/(double)m);
            cout << res << endl;
        }
        else if(xp < x && yp >= y){
            int sum1 = x * y;
            int sum2 = xp * yp;
            int jq = xp*y;
            int m = sum1 + sum2 - jq;
            double res = (double)jq/(double)m;

            sum2 = (x-xp)*yp;
            jq = (x-xp)*y;
            m = sum1 + sum2 - jq;
            res = max(res,(double)jq/(double)m);
            cout << res << endl;
        }
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--){
        solve();
    }
    return 0;
}

M

解析

dp,利用几个样例可以知道
假设(i,j)是用i个仙贝分给j个人,那么(i,j)的状态可以由(i-k,j-1)转移过来(即第i个人分k个仙贝)
这样一来转移方程和状态就可以确定 \(dp[i][j] = max(dp[i-k][j-1] + k*1.0/i,dp[i][j])\)
刚开始写的时候把n,m看反了,不想改后面的了,就swap了一下

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
double dp[505][505];
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
    }
inline void print(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
        putchar(x%10+'0');
    }
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin >> n >> m;
    swap(n,m);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            for(int k = 0; k <= i; k++){
                dp[i][j] = max(dp[i-k][j-1] + k*1.0/i,dp[i][j]);
            }
        }
    }
    cout << fixed << setprecision(6);
    cout << dp[n][m] << endl;
    return 0;
}

G

解析

通过样例可以算出每个数最多经过不超过20次操作一定能收敛成一个定值(超过100的逐渐变小,小于100的逐渐变大)
可以用set维护数组的下标
每当有一个数达到收敛值时,就erase
时间复杂度为 \(O(k*nlogn)\)

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'

const int N = 1e5 + 5;
int n,m,a[N],ans;
set<int> st;
int f(int x){
    return round(sqrt(x)*10);
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m;
    for(int i=1;i<=n;i++){
        cin >> a[i];
        ans += a[i];
        if(f(a[i]) != a[i]){
            st.insert(i);
        }
    }
    st.insert(n+1);
    int op,l,r,k;
    while(m--){
        cin>>op;

        if(op==1){
            cin >> l >> r >> k;
            int pos=l;
            while(1){
                int rpk = *st.lower_bound(pos);
                if(rpk>r) break;
                for(int i = 1;i <= min(k,(int)20); i++){
                    ans -= a[rpk];
                    a[rpk] = f(a[rpk]);
                    ans += a[rpk];
                }
                if(f(a[rpk]) == a[rpk]){
                    st.erase(rpk);
                }
                pos = rpk + 1;
            }
        }
        else{
            cout << ans << endl;
        }
    }  
    return 0;
}

posted @ 2023-01-17 16:01  Sun-Wind  阅读(21)  评论(0编辑  收藏  举报