• Educational Codeforces Round 61 (Rated for Div. 2) D,F题解


    D. Stressful Training

    题目链接:https://codeforces.com/contest/1132/problem/D

    题意:

    有n台电脑,每台电脑都有初始电量ai,也有一个耗电量bi,意即每1s耗电多少,现在你有一个充电器,它每s可以给一台电脑充x的点亮。

    问x最少为多少,可以让所有电脑直至k时刻,点亮都不小于0。

    题解:

    我们考虑贪心,先给最需要充电的电脑充电,然后二分答案x去检验。大概思路就是这样吧...但是实现起来还是有点困难。

    首先处理出每个电脑最晚需要充电的时刻ti,然后每次用一个指针找到第一个需要充电的时刻,不断给这个电脑充电直至这个电脑在下一秒不会没电,然后就更新它的时间。

    这个时间复杂度是O(n+k)的,如果用优先队列,代码实现起来就比较简单,但是时间复杂度就多个log,但是cf评测机比较好,还是可以卡过的。

    具体细节建议自己去实现一下吧,这样才有更深的体会,代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+5;
    ll n,k;
    ll a[N],b[N],c[N];
    vector <ll> vec[N];
    bool check(ll x){
    //x=25;
        for(int i=1;i<=k;i++) vec[i].clear();
        memcpy(c,a,sizeof(a));
        for(int i=1;i<=n;i++){
            ll pos=a[i]/b[i]+1;
            if(pos<=k){
                vec[pos].push_back(i);
                c[i]=a[i]%b[i];
            }
        }
        ll last=1;
        for(int i=1;i<=k;i++){
            while(last<=k&&vec[last].empty()) last++;
            if(last==k+1) return true;
            if(last<i) return false ;
            int now = vec[last].back();
            if(c[now]+x<b[now]){
                c[now]+=x;
                continue ;
            }
            c[now]+=x;
            vec[last].pop_back();
            if(last+c[now]/b[now]<=k){
                vec[last+c[now]/b[now]].push_back(now);
                c[now]%=b[now];
            }
        }
        return true;
    }
    int main(){
        cin>>n>>k;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++) cin>>b[i];
        ll l=0,r=1e16,mid;
        while(l<r){
            mid=(l+r)/2;
            if(check(mid)) r=mid;
            else l=mid+1;
        }
        if(l==1e16) cout<<-1;
        else cout<<r;
        return 0;
    }
    View Code

    F. Clear the String

    题目链接:https://codeforces.com/contest/1132/problem/F

    题意:

    给出一个字符串,每次可以消去相同的连续字符,然后问最少需要几次能将这个字符串全部消去。

    题解:

    这题主要的关键就是发现无论怎么消,都会和两边的一起消。那么我们就可以类似于区间dp那样通过枚举确定两个边界进行转移了。

    枚举中间点的时候,如果发现那个中间点和左端点的字符相同,那么我们就可以将那个中间点和左端点一起消。

    反正这个题的解法很多就是了~转移方程也很多。

    具体见代码吧:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 505,INF = 0x3f3f3f3f3f;
    int n;
    char s[N];
    int dp[N][N];
    int main(){
        scanf("%d",&n);
        scanf("%s",s+1);
        memset(dp,INF,sizeof(dp));
        for(int i=1;i<=n;i++) dp[i][i]=1;
        for(int l=2;l<=n;l++){
            for(int i=1;i<=n;i++){
                int j=i+l-1;
                if(j>n) break ;
                for(int k=i;k<j;k++){
                    if(s[i]==s[j]) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]-1);
                    else dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
                }
            }
        }
        cout<<dp[1][n];
        return 0;
    }
    View Code
  • 相关阅读:
    MyISAM和InnoDB的区别
    MySQL——索引与优化
    jquery选择器及效率问题
    Mac 可设置环境变量的位置、查看和添加PATH环境变量
    javascript默认中文(汉字/标点)长度均为1的解决
    苹果下抓屏截屏方法 包括全屏、选择区域、窗口抓屏等
    java实现window phone推送通知
    设计模式总结
    NHibernate 帮助类(单例实际运用)
    访问者模式
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/10507381.html
Copyright © 2020-2023  润新知