• bzoj1897. tank 坦克游戏(决策单调性分治)


    题目描述

    有这样一款新的坦克游戏。在游戏中,你将操纵一辆坦克,在一个N×M的区域中完成一项任务。在此的区域中,将会有许多可攻击的目标,而你每摧毁这样的一个目标,就将获得与目标价值相等的分数。只有获得了最高的分数,任务才算完成。同时,为了增加游戏的真实性和难度,该游戏还做了以下的限制:

    1)坦克有射程r的限制。为方便计算,射程r规定为:若坦克位于(x, y)格,则它可攻击的目标(x1, y1)必须满足|x-x1|, |y-y1|∈[0, r]。

    2)对坦克完成任务的时间有严格限制,规定为t秒。其中,坦克每进行一次移动都需1秒的时间,每攻击一个目标也需1秒的时间。时间一到t秒,便对此次任务进行记分。

    3)坦克最初位于左上角,且移动方向只准是向右或向下,每次只允许移动一格。

    在以上的限制条件下,要完成该任务便成为了一件很难事情。因此,你必须为此编写一个程序,让它助你完成这个艰巨的任务。

    输入格式

    第一行四个整数N、M、r、t,分别表示区域的长、宽,以及射程和完成任务时间。

    接下来N行是一个N×M的矩阵,对应每个位置上目标的价值。

    输出格式

    输出文件仅一个数max,即该任务中可得到的最高分数。

    样例

    样例输入

    5 5 2 7
    0 5 0 0 4
    0 0 0 0 2
    0 0 0 0 0
    0 0 0 0 0
    5 0 3 0 11

    样例输出

    21

    数据范围与提示

    1≤N、M≤500,1≤r≤100,1≤t≤250。

    对于20%的数据有:1≤N、M≤10。

    对于60%的数据有:1≤N、M≤50,1≤r≤10。

    对于80%的数据有:1≤N、M≤100,1≤r≤20。


    设$f[i][j][k]$表示到$(i,j)$为止打$k$个的最大价值

    注意到每步打目标的个数一定是单调不降的

    证明....挂一神犇的blog

    每次转移时用决策单调性分治优化

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define re register
    using namespace std;
    int read(){
        char c=getchar(); int x=0;
        while(c<'0'||c>'9') c=getchar();
        while('0'<=c&&c<='9') x=x*10+c-48,c=getchar();
        return x;
    }
    #define N 505
    int cmp(int A,int B){return A>B;}
    int n,m,R,T,ans,k=1,a[N][N],f[2][N][253],h[N*N],tp,g[N],v[N];
    void solve(int l,int r,int dl,int dr){
        if(l>r||dl>dr) return ; 
        int mm=(l+r)/2,dm=dl;
        for(int i=dl;i<=min(mm,dr);++i)
            if(v[mm]<g[mm-i]+h[i])
                v[mm]=g[mm-i]+h[i],dm=i;
        solve(l,mm-1,dl,dm);
        solve(mm+1,r,dm,dr);
    }
    int main(){
        n=read(); m=read(); R=read(); T=read();
        for(re int i=1;i<=n;++i)
            for(re int j=1;j<=m;++j)
                a[i][j]=read();
        for(re int i=1;i<=R+1;++i)
            for(re int j=1;j<=R+1;++j)
                if(a[i][j]) h[++tp]=a[i][j];
        sort(h+1,h+tp+1,cmp); tp=min(tp,T);//注意最多取T个
        for(re int i=1;i<=tp;++i) f[1][1][i]=f[1][1][i-1]+h[i];
        int _n=max(1,n-R),_m=max(1,m-R);
        for(re int i=1;i<=_n;++i,k^=1)
            for(re int j=1;j<=_m;++j){
                int lim=T-i-j+2;
                if(lim<=0) continue;
                if(i>1){
                    for(re int u=0;u<=lim;++u) v[u]=g[u]=f[k^1][j][u];
                    tp=0;
                    for(re int u=max(1,j-R);u<=min(m,j+R);++u)
                        if(a[i+R][u]) h[++tp]=a[i+R][u];
                    sort(h+1,h+tp+1,cmp);
                    for(re int u=1;u<=tp;++u) h[u]+=h[u-1];
                    solve(1,lim,0,tp);
                    for(re int u=0;u<=lim;++u) f[k][j][u]=max(f[k][j][u],v[u]);
                }
                if(j>1){
                    for(re int u=0;u<=lim;++u) v[u]=g[u]=f[k][j-1][u];
                    tp=0;
                    for(re int u=max(1,i-R);u<=min(n,i+R);++u)
                        if(a[u][j+R]) h[++tp]=a[u][j+R];
                    sort(h+1,h+tp+1,cmp);
                    for(re int u=1;u<=tp;++u) h[u]+=h[u-1];
                    solve(1,lim,0,tp);
                    for(re int u=0;u<=lim;++u) f[k][j][u]=max(f[k][j][u],v[u]);
                }
                while(lim) ans=max(ans,f[k][j][lim--]);
            }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    SandBoxieLPC通信
    process map
    分块/分块除法
    (分块除法,题目数学式子的提取,%的除法转化和%的取余数的应用)
    并发编程四(1) 线程同步 生产者消费者
    vue系列 箭头函数和this
    并发编程四(3) 线程同步 Event信号传递
    金融支付财务
    2.Vue系列 基础语法
    安全测试工具
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/11359685.html
Copyright © 2020-2023  润新知