[Codeforces Round #642 (Div. 3)] :

 

D:
思路:暴力维护优化.
用大顶堆来维护,删除元素同时放入两半区间
注意的是优先队列默认为最大堆,所以cmp重载,符号需要都和我们想要的结果相反.即(> > = <,> < = >).

Code:

typedef tuple<int,int,int> ple;//len,l,r
struct cmp
{
    bool operator()(const ple &a,const ple &b)
    {
        if(get<0>(a) == get<0>(b)) return get<1>(a) > get<1>(b);
        return get<0>(a) < get<0>(b);
    }
};
int a[N];
int main()
{
    int t;sd(t);
    while(t--)
    {
        priority_queue<ple,vector<ple>,cmp> Q;
        int n;sd(n);
        Q.push(ple(n,1,n));
        for(int i=1;i<=n;++i)
        {
            int L = get<1>(Q.top()),r = get<2>(Q.top());
            Q.pop();
            int mid = L+r>>1;
            a[mid] = i;
            if(L != r)
            {
                int dis1 = mid-L,dis2 = r-mid;
                Q.push(ple(mid-L,L,mid-1));
                Q.push(ple(r-mid,mid+1,r));
            }
        }
        for(int i=1;i<=n;++i) printf("%d%c",a[i],i==n?'\n':' ');
    }
    system("pause");
    return 0;
}
View Code

E:

思路:枚举首位,dp转移.
在k的控制下,首位肯定是[1,k].
然后i+k,.....
定义:
dp[i][0]为i位置选0时的最小代价.
dp[i][1]为i位置选1时的最小代价.
转移思路:
若i位置为1.
i-k为1,保证[i+k,i]都为0. dp[i][1] = dp[i-k][1]+(中间为0的代价.)
i-k为0,保证[i+k,i]前面的都为0. dp[i][0] = 前面都为0的代价
i位置为0.
i-k为1,保证[i+k,i]都为0. dp[i][1] = dp[i-k][1]+(中间为0的代价)
i-k为0,保证[i+k,i]都为0. dp[i][0] = dp[i-k][0]+(中间为0的代价).
0的删除代价可以前缀和维护.
inline int read()
{
    int x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
int dp[N][2],sum[N];
int main()
{
    int t;sd(t);
    while(t--)
    {
        int n,k,j;
        n = read();k = read();
        char s[N];scanf("%s",s+1);
        sum[0] = 0;
        for(int i=1;i<=n;++i)
        {
            sum[i] = sum[i-1]+(s[i] == '1'?1:0);
        }
        int ans = INF;
        for(int i=1;i<=k;++i)
        {
            dp[i][0] = sum[i-1]+(s[i] == '1');
            dp[i][1] = sum[i-1]+(s[i] == '0');
            for(j=i+k;j<=n;j+=k)
            {
                dp[j][1] = min(sum[j-1],dp[j-k][1]+sum[j-1]-sum[j-k])+(s[j] == '0');
                dp[j][0] = min(dp[j-k][0],dp[j-k][1])+sum[j-1]-sum[j-k]+(s[j] == '1');
            }
            j -= k;
            ans = min(ans,min(dp[j][1],dp[j][0])+sum[n]-sum[j]);
        }
        pr(ans);
    }
    system("pause");
    return 0;
}
View Code

F:

思路:

首先要明白:最优解的情况下最优路径上肯定有最少一个点保存不变.

证明:

对于最优路径[a1,a2,a3...an]:

最大值肯定<=max(a1~an),因为只能减小不能增大.

那么在往所有数肯定都在缩小的范围内变动,那么保持有一个点不动,答案更优

那么,我们可以去枚举不变的那个点:

不变的点确定后,其他的点的高度也可以确定,然后dp转移统计最优的解.

对于dp的转移:

我们确定了一个点x,y不变.

进行二次dp.第一次统计(x,y)到(1,1)上的有影响的点的dp值.

第二统计(x,y)到(n,m)上的有影响的点的dp值。

那么最终结果就是dp[1][1]+dp[n][m]..

注意这里的有影响的点,当(x,y)确定是路径上的点后,那些走不到(x,y)的点或者(x,y)走不到的点不用管.

所以我们dp的时候是

i ~ [x~1],j~[y,1] 和 i~[x,n],j~[y~m].

int n,m;
LL mp[105][105],dp[105][105],he[105][105],ans;
void slove(int x,int y)
{
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) dp[i][j] = INF,he[i][j] = mp[x][y]-(x-i)-(y-j);//先处理出x,y不变时,其他点的高度(曼哈顿距离).
    dp[x][y] = 0,he[x][y] = mp[x][y];
    for(int i=x;i>=1;--i)
    {
        for(int j=y;j>=1;--j)
        {
            if(i == x && j == y) continue;
            if(mp[i][j] < he[i][j]) continue;//很显然无法增加高度,所以这种情况下走不了.
            LL ma1,ma2;
            if(i+1 <= n)//控制下下标边界
            {
                ma1 = dp[i+1][j]+mp[i][j]-he[i][j];//计算下这个点变成这个高度后的贡献.
                dp[i][j] = min(dp[i][j],ma1);
            }
            if(j+1 <= m) 
            {
                ma2 = dp[i][j+1]+mp[i][j]-he[i][j];
                dp[i][j] = min(dp[i][j],ma2); 
            }
        }
    }
    for(int i=x;i<=n;++i)
    {
        for(int j=y;j<=m;++j)
        {
            if(i == x && j == y) continue;
            if(mp[i][j] < he[i][j]) continue;
            LL ma1,ma2;
            if(i-1 >= 1)
            {
                ma1 = dp[i-1][j]+mp[i][j]-he[i][j];
                dp[i][j] = min(dp[i][j],ma1);
            }
            if(j-1 >= 1)
            {
                ma2 = dp[i][j-1]+mp[i][j]-he[i][j];
                dp[i][j] = min(dp[i][j],ma2);
            }
        }
    }
    ans = min(ans,dp[1][1]+dp[n][m]);
}
int main()
{
    int t;sd(t);
    while(t--)
    {
        ans = INF;
        sdd(n,m);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j) sld(mp[i][j]);
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=m;++j)
            {
                slove(i,j);
            }
        }
        plr(ans);
    }
    system("pause");
    return 0;
}
View Code

 

posted @ 2020-05-16 11:08  levill  阅读(118)  评论(0编辑  收藏  举报