zoukankan      html  css  js  c++  java
  • Identical Day 题解(思维)

    题目连接

    题目大意

    给你一个长度为(n(nleq1e5))(01)

    求最少使得多少个(1)变为(0)后这个串的价值小于(k(kle1e10))

    串的价值为所有连续为(1)的串的价值

    一段长度为(len)连续为(1)的价值为(len*(len+1)/2)

    例如(0111101)的价值为(frac{4 imes5}{2}+frac{1 imes2}{2}=11)

    题目思路

    这个题目我一开始想的过于简单了,首先我认为很容易想到优先队列贪心

    我用的是每次拿出最长的那一段然后直接中间分隔,用优先队列去维护

    但是可以想一下如果一段要分为三段,那么最终我分的比例等于(1:1:2)

    但是显然是要(1:1:1) 即三等分,但是我那样第一步是分为两份肯定不行

    然后我就不不会了。。。

    其实正解和这个差不了太多,就是差值最大

    (cal(a,b))为一段长度为(a)的连续的(1),中间人为变了(b)个的最小价值

    ((a,b))这个放入优先队列,那么优先队列只要比较(cal(a,b)-cal(a,b+1))即可

    (cal(a,b))这个函数计算也很简单(b)(0),那么分为(b+1)

    肯定是要等分每一份为(x=(a-b)/(b+1)),而多余了(y=(a-b)\%(b+1))

    那么肯定是给(y)份每一个多(1)

    • ((b+1-y))份长度为$x $
    • (y)份长度为(x+1)

    以前写过类似的题目,感觉这种题目就是要往差值方面去考虑,不过这个稍微难一点点

    代码

    #include<bits/stdc++.h>
    #define debug printf("
     I am here
    ");
    #define fi first
    #define se second
    #define pii pair<int,int>
    typedef long long ll;
    const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    using namespace std;
    ll n,k;
    char s[maxn];
    ll cal(ll a,ll b){
        // 长度为a个1 中间有b个0
        ll x=(a-b)/(b+1);
        ll y=(a-b)%(b+1);
        ll ans=x*(x+1)/2*(b+1-y)+(x+1)*(x+2)/2*y;
        return ans;
    }
    ll dif(ll a,ll b){
        return cal(a,b)-cal(a,b+1);
    }
    struct node{
        ll x,y;
        friend bool operator<(node a,node b){
            return dif(a.x,a.y)<dif(b.x,b.y);
        }
    };
    priority_queue<node> pq;
    int main(){
        scanf("%lld%lld",&n,&k);
        scanf("%s",s+1);
        ll len=0,sum=0;
        for(int i=1;i<=n;i++){
            if(s[i]=='1'){
                len++;
            }
            if(s[i]=='0'||i==n){
                if(len!=0){
                    sum+=len*(len+1)/2;
                    pq.push({len,0});
                }
                len=0;
            }
        }
        ll ans=0;
        while(sum>k){
            ans++;
            node temp=pq.top();
            pq.pop();
            sum-=dif(temp.x,temp.y);
            if(temp.x==temp.y+1) continue;
            pq.push({temp.x,temp.y+1});
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
    
    卷也卷不过,躺又躺不平
  • 相关阅读:
    Docker用途 & 和tomcat的区别
    Ubuntu安装Redis
    Ubuntu查看和设置Root账户
    Oracle常用语句
    Redis知识总结
    Blazor学习笔记01: 使用BootstrapBlazor组件 创建一个具有单表维护功能的表格页面
    NET Core之积沙成塔01: 解决Visual Studio 2019 代码提示为英文
    MySQL系统自带的数据库information schema
    Windows安装mysql方法
    数据库之概念
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/14881005.html
Copyright © 2011-2022 走看看