Codeforces Round #210 (Div. 1)

http://codeforces.com/contest/360

A. Levko and Array Recovery
从后往前根据操作给每个位置赋值,然后还要从前往后判断操作是否可行。

// Author : JayYe  Created Time: 2013-11-12 20:29:06
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
using namespace std;
typedef __int64 ll;

const int maxn = 5000 + 5;

struct PP {
    int op, l, r, v;
}a[maxn];

bool vis[maxn];
ll ans[maxn], pr[maxn];

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1;i <= m; i++)
        scanf("%d%d%d%d", &a[i].op, &a[i].l, &a[i].r, &a[i].v);
    for(int i = m;i >= 1; i--) {
        if(a[i].op == 1) {
            for(int j = a[i].l;j <= a[i].r; j++) if(vis[j])
                ans[j] -= a[i].v;
        }
        else {
            for(int j = a[i].l;j <= a[i].r; j++) {
                if(!vis[j]) {
                    vis[j] = true;
                    ans[j] = a[i].v;
                }
                else if(ans[j] >= a[i].v){
                    ans[j] = a[i].v;
                }
            }
            bool ok = 0;
            for(int j = a[i].l;j <= a[i].r; j++) if(ans[j] == a[i].v) {
                ok = 1; break;
            }
            if(!ok) return puts("NO"), 0;
        }
    }
    for(int i = 1;i <= n; i++) {
        if(!vis[i])
            ans[i] = 0;
        pr[i] = ans[i];
    }
    bool ok = 1;
    for(int i = 1;i <= m; i++) {
        if(a[i].op == 1) {
            for(int j = a[i].l;j <= a[i].r; j++)
                ans[j] += a[i].v;
        }
        else {
            ll mx = ans[a[i].l];
            for(int j = a[i].l;j <= a[i].r; j++)
                mx = max(mx, ans[j]);
            if(mx != a[i].v)    return puts("NO"), 0;
        }
    }
    puts("YES");
    for(int i = 1;i <= n; i++)
        printf("%I64d ", pr[i]);
    puts("");
    return 0;
}

      
      
     
     
    
    

B. Levko and Array

给你n个数,最多可以改变k个数,使得val = max( a(i), a(i+1) )尽量小,最小是多少。 n <= 2000


思路:首先考虑高复杂度的,设dp[i][j]表示 i 这个位置不变,前面已经改变了j个数最小的val值。那么 dp[i][j]可以由 dp[k][j-1] k < i转移过来,表示i位置不变k位置也不变中间的随意变,所以 dp[i][j] = min( dp[k][j-1] + i-j-1) ,每个转移是O(n)的,总复杂度是O(n^3)。 

二分答案X,复杂度就降低到了O(n^2logn)。。就done了

// Author : JayYe  Created Time: 2013-11-13 11:14:35
#include 
  
  
   
   
#include 
   
   
    
    
#include 
    
    
     
     
using namespace std;
typedef __int64 ll;

const int maxn = 2000 + 5;
const ll INF = 1LL<<31;

int n, k;
ll a[maxn], dp[maxn];

ll ABS(ll x) {
    return x > 0 ? x : -x;
}

bool doubi(ll d) {
    dp[1] = 0;
    for(int i = 2;i <= n; i++) {
        dp[i] = INF;
        for(int j = i-1;j >= 1; j--) {
            if((ABS(a[i] - a[j]) + i-j-1)/(i-j) <= d)
                dp[i] = min(dp[i], dp[j] + i-j-1);
        }
        if(i - 1 <= k)  dp[i] = min(dp[i], i-1LL);
    }
    for(int i = 1;i < n; i++)
        dp[n] = min(dp[n], dp[i] + n-i);
    return dp[n] <= k;
}

int main() {
    scanf("%d%d", &n, &k);
    for(int i = 1;i <= n; i++)
        scanf("%I64d", &a[i]);
    ll l = 0, r = INF;
    while(l < r) {
        ll mid = (l + r)/2;
        if(doubi(mid))  r = mid;
        else    l = mid+1;
    }
    printf("%I64d\n", r);
    return 0;
}

    
    
   
   
  
  


C. Levko and Strings

题意自己理解。。


思路: 设dp[i][j]表示i这个位置不等于s[i]的产生的值为j的情况数。

dp[i][j]一个转移是由前一个与原串字母不一样的转移过来的。则

如果上一个不一样的字母在cur这个位置,那么如果t[i] > s[i],可以产生 (n-i+1)*(i-cur)的值。

转移的复杂度是O(n*logn)的,可以自己好好想想。具体见代码

// Author : JayYe  Created Time: 2013-11-13 15:45:52
#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
using namespace std;
typedef __int64 ll;

const int maxn = 2000 + 5;
const int mod = 1000000007;

char s[maxn];
ll dp[maxn][maxn], sum[maxn];

int main() {
    int n, k;
    scanf("%d%d", &n, &k);
    scanf("%s", s + 1);
    dp[0][0] = 1;
    sum[0] = 1;
    for(int i = 1;i <= n; i++) {
        for(int j = 0;j <= k; j++)
            dp[i][j] = sum[j]*(s[i]-'a');
        int cur = i-1;
        while(cur >= 0 && (i-cur)*(n-i+1) <= k) {
            for(int j = 0;j <= k; j++) {
                if(j + (i-cur)*(n-i+1) > k) break;
                dp[i][j+(i-cur)*(n-i+1)] = (dp[i][j+(i-cur)*(n-i+1)]+dp[cur][j]*('z'-s[i]))%mod;
            }
            cur--;
        }
        for(int j = 0;j <= k; j++)
            sum[j] = (sum[j] + dp[i][j])%mod;
    }
    
    printf("%I64d\n", sum[k]);
    return 0;
}

     
     
    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值