[Codeforces #210] Tutorial

Link:

Codeforces #210 传送门

A:

贪心,对每个值都取最大值,不会有其他解使答案变优

#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef long long ll;
typedef pair<int,int> P;
typedef double db;
const int MAXN=5005,INF=1<<30;
struct data{int op,l,r,x;}dat[MAXN];
int n,m,mx[MAXN],vis[MAXN];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d%d",&dat[i].op,&dat[i].l,&dat[i].r,&dat[i].x);
    for(int i=1;i<=n;i++)
    {
        int tmp=0;mx[i]=INF;
        for(int j=1;j<=m;j++)
            if(dat[j].op==1&&i>=dat[j].l&&i<=dat[j].r) 
                tmp+=dat[j].x;
            else if(dat[j].op==2&&i>=dat[j].l&&i<=dat[j].r)
                mx[i]=min(mx[i],dat[j].x-tmp);
    }
    for(int i=1;i<=n;i++)
    {
        if(mx[i]==INF) mx[i]=0;
        int tmp=mx[i];
        for(int j=1;j<=m;j++)
            if(dat[j].op==1&&i>=dat[j].l&&i<=dat[j].r) 
                tmp+=dat[j].x;
            else if(dat[j].op==2&&i>=dat[j].l&&i<=dat[j].r&&tmp==dat[j].x)
                vis[j]++;
    }
    for(int i=1;i<=m;i++)
        if(dat[i].op==2&&!vis[i]) return puts("NO"),0;
    puts("YES");
    for(int i=1;i<=n;i++) 
        printf("%d ",mx[i]);
    return 0;
}
Problem A

 

B:

答案可行性单调,二分答案

每次判断用$dp[i]$表示到$i$只要要删多少个数,$i$必取

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=2e3+10;
int n,k,l,r,dat[MAXN],dp[MAXN];

bool check(int x)
{
    int ret=n;
    for(int i=1;i<=n;i++) dp[i]=i-1;
    for(int i=2;i<=n;i++)
        for(int j=1;j<i;j++)
            if(abs(dat[i]-dat[j])<=1ll*x*(i-j))
                dp[i]=min(dp[i],dp[j]+i-j-1);
    for(int i=1;i<=n;i++)
        ret=min(ret,dp[i]+n-i);
    return ret<=k;
}

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&dat[i]);
    l=0;r=2e9;
    while(l<=r)
    {//注意爆long long
        int mid=l/2+r/2+(l%2+r%2)/2;
        if(check(mid)) r=mid-1;
        else l=mid+1;
    }
    printf("%d",l);
    return 0;
}
Problem B

$i$必取这个条件一定要加,否则无法转移

同时注意二分时$l+r$可能爆$longlong$

 

C:

想到从前往后$dp$,每次按以$i$为左端点时对答案的贡献转移

但这样在$t[i]=s[i]$时是后项相关的,不符合$dp$要求

因此要将$t[i]=s[i]$合并在$t[i]>s[i]$中计算,$t[i]>s[i]$时的贡献变为$(pre+1)*(n-i+1)$

$dp[i][j]$:以前$i$位为左端点结果为$j$的方案数,分$t[i]>s[i]$与$t[i]<s[i]$枚举$pre$转移

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN=2e3+10,MOD=1e9+7;
int n,k;char s[MAXN];
ll pre[MAXN][MAXN],dp[MAXN][MAXN];

int main()
{
    scanf("%d%d%s",&n,&k,s+1);
    dp[0][0]=pre[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=k;j++)
        {
            dp[i][j]=pre[i-1][j]*(s[i]-'a')%MOD;
            for(int k=0;(k+1)*(n-i+1)<=j&&k<i;k++)
                (dp[i][j]+=dp[i-k-1][j-(k+1)*(n-i+1)]*('z'-s[i]))%=MOD;
            pre[i][j]=(pre[i-1][j]+dp[i][j])%MOD;
        }
    printf("%lld",pre[n][k]);
    return 0;
}
Problem C

 

posted @ 2018-08-29 11:58  NewErA  阅读(126)  评论(0编辑  收藏  举报