zoukankan      html  css  js  c++  java
  • Codeforces Round #466

    A. Points on the line

    题意

    给定一条直线上(n)个点,要求去掉最少的点,使得直线上相距最远的两个点的距离(leq d).

    思路

    枚举长度为(d)的区间。

    Code

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    using namespace std;
    typedef long long LL;
    int a[110];
    int main() {
        int n, d;
        scanf("%d%d", &n, &d);
        F(i, 0, n) {
            int x;
            scanf("%d", &x);
            ++a[x];
        }
        F2(i, 1, 100) a[i] += a[i-1];
        int ans = min(a[100]-a[d], a[99-d]);
        F(i, 1, 100-d) {
            int l = i, r = i+d;
            ans = min(ans, a[l-1]+a[100]-a[r]);
        }
        printf("%d
    ", ans);
        return 0;
    }
    
    

    B. Our Tanya is Crying Out Loud

    题意

    初始数为(n),两种操作:

    1. 减一:代价为(A)
    2. 除以(k):代价为(B)且仅当整除时可进行此操作

    求最小代价使(n)变为(1).

    思路

    一旦某一次除法的代价(gt)减法的(等效)代价,则直接减到(1),否则进行除法操作。

    Code

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    using namespace std;
    typedef long long LL;
    int main() {
        LL n,k,a,b;
        scanf("%I64d%I64d%I64d%I64d",&n,&k,&a,&b);
        LL ans = 0;
        bool flag = false;
        while (n!=1) {
            if (n%k) {
                ans += n%k*a;
                n = n/k*k;
            }
            if (n/k*(k-1)*a <= b) {
                ans += (n-1)*a;
                break;
            }
            ans += b;
            n /= k;
        }
        printf("%I64d
    ", ans);
        return 0;
    }
    
    

    C. Phone Numbers

    题意

    在字符集(sum)范围内,求长度为(k)的,比给定字符串(s)大的,最小的字符串。

    思路

    (len=|s|)

    1. (len<k),在(s)之后补(k-len)个最小的字符
    2. (len>k),首先将之后的多余部分截断,再将前面的部分 加一(操作与数字+1同理)。

    Code

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    #define maxn 100010
    using namespace std;
    typedef long long LL;
    char s[maxn];
    int mp[256], ch[30], a[maxn];
    bool vis[256];
    int main() {
        int n, k, tot=0;
        scanf("%d%d", &n,&k);
        scanf("%s",s);
        int len = strlen(s);
        F(i, 0, len) {
            if (tot==26) break;
            if (!vis[s[i]]) {
                ch[tot++] = s[i];
                vis[s[i]] = true;
            }
        }
        sort(ch, ch+tot);
        F(i, 0, tot) mp[ch[i]] = i;
        if (k>len) {
            while (len<k) s[len++] = ch[0];
            s[len] = '';
            puts(s);
            return 0;
        }
        s[k] = '';
        F(i, 0, k) a[i] = mp[s[i]];
        int i = k-1;
        while (true) {
            ++a[i];
            if (a[i]<tot) break;
            a[i--] = 0;
        }
        F(i, 0, k) s[i] = ch[a[i]];
        puts(s);
        return 0;
    }
    
    

    D. Alena And The Heater

    题意

    给定数组(a),按一定的规则可以生成数组(b). 规则如下:

    • (b_1=b_2=b_3=b_4=0.)
    • For all (5leq ileq n):
      --- (b_i=0) if (a_i,a_{i-1},a_{i-2},a_{i-3},a_{i-4}gt r) and (b_{i-1},b_{i-2},b_{i-3},b_{i-4}=1)
      --- (b_i=1) if (a_i,a_{i-1},a_{i-2},a_{i-3},a_{i-4}lt l) and (b_{i-1},b_{i-2},b_{i-3},b_{i-4}=0)
      --- (b_i=b_{i-1}) otherwise

    思路

    只需确定每个转折点,对于其及其前面共(5)个数字,由(1)变为(0)则取最小值使(r)比它小,由(0)变为(1)则取最大值使(l)比它大。

    至于中间则无需考虑,因为题目保证有解,而要不发生变化,即条件不成立,则只要(l)尽量小,(r)尽量大即可。

    Code

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    #define inf 1000000000
    #define maxn 100010
    using namespace std;
    char s[maxn];
    int a[maxn];
    typedef long long LL;
    int minn(int p) { int ret = a[p]; F(i, p+1, p+5) ret = min(ret, a[i]); return ret; }
    int maxx(int p) { int ret = a[p]; F(i, p+1, p+5) ret = max(ret, a[i]); return ret; }
    int main() {
        int n;
        scanf("%d", &n);
        F(i, 0, n) scanf("%d", &a[i]);
        scanf("%s", s);
        bool flag = false;
        int r = inf, l = -inf;
        F(i, 0, n) {
            if (s[i]-'0'!=flag) {
                if (flag) r = min(r, minn(i-4)-1);
                else l = max(l, maxx(i-4)+1);
                flag = !flag;
            }
        }
        printf("%d %d
    ", l, r);
        return 0;
    }
    

    E. Cashback

    题意

    给定一个数组,将其分割成若干段,将每一段的(value)求和,要求得最小值。

    (value)定义如下:
    对于长度为(k)的数组(b),其(value)为除了(lfloorfrac{k}{c} floor)小元素以外的元素的和。
    例如:[3,1,6,5,2], c=2,其value为3+6+5=14.

    思路

    首先一个显然的事实是:假设不分段而作为一个整体能去除掉(m)个元素,那分段去除掉的元素个数必然(leq m).

    然而又有另一个显然的事实:不分段去掉(m)个元素之和(sum1),与分段去掉(m)个元素(sum2)相比,显然(sum1leq sum2). 因为不分段的话去掉的是一整段的(m)个最小,而分段的话去掉的是(m)段中每段中的最小。

    综合上面两个事实,应该尽量多分段,又要保证每一段分的有价值,即,最理想的情况就是每(c)个元素分一段。

    于是(dp)如下:

    (dp[i] = min(dp[i-1]+a[i], dp[i-c]+sum[i-c+1..i]-min[i-c+1..i]))

    至于最小值,直接用ST表进行RMQ即可,比赛时用的是单调队列维护的...。

    Code

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    #define maxn 100010
    using namespace std;
    typedef long long LL;
    LL a[maxn], sum[maxn], dp[maxn];
    int st[maxn];
    int main() {
        int n, c;
        scanf("%d%d", &n, &c);
        F2(i, 1, n) {
            scanf("%I64d", &a[i]);
            sum[i] = sum[i-1] + a[i];
        }
        if (c==1) { printf("%d
    ", 0); return 0; }
        dp[1] = a[1];
        int l=0, r=0; st[r++] = 1;
        F2(i, 2, n) {
            LL minn = dp[i-1]+a[i];
            while (r>l && a[st[r-1]]>=a[i]) --r;
            st[r++] = i;
            if (i-c>=0) {
                while (r>l && st[l]<=i-c) ++l;
                minn = min(minn, dp[i-c]+sum[i]-sum[i-c]-a[st[l]]);
            }
            dp[i] = minn;
        }
        printf("%I64d
    ", dp[n]);
        return 0;
    }
    
    
  • 相关阅读:
    UI第十七讲.图片异步加载(包括第三方), KVO, KVC
    第二十一讲.UICollectionView(集合视图)以及瀑布流效果, 通知中心(NSNotificationCenter).
    UI第十九讲:数据库
    UI第十八讲.初级数据持久化 (沙盒, 简单写入对象, 归解档, NSUserDefaults写入读取文件 )
    第十四讲(下) 可视化方式的实现通讯录.(及storyboard方式)
    第十六讲.网络编程 (HTTP协议)
    wslgit
    MyBatis时间比较
    layer开启与关闭加载层
    MyBatis中choose when正确写法
  • 原文地址:https://www.cnblogs.com/kkkkahlua/p/8468896.html
Copyright © 2011-2022 走看看