并不知道叠虚是什么意思,有人来教教吗/kk
没想到解法,只觉得这题搜索和DP都做不了,所以用堆维护,贪心了一下,没证明,贪错了(((
正解给的是按力量值s和重量值w之和从小到大排序,排完序之后的序列就是从上至下的叠放顺序
证明:
码:(原来错误的码改的,丑死了)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=100010;
int n,ans=0;
struct node{
    int w,s,ss;//ss是w和s的和
}op[N];
bool cmp(node a,node b){
    return a.ss<b.ss;//按ss排序
}
inline int read(){
    int x=0,y=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) y=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar();
    return x*y;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++) op[i].w=read(),op[i].s=read(),op[i].ss=op[i].w+op[i].s;
    sort(op+1,op+1+n,cmp);
    
    int pos=-op[1].s;
    ans=pos;
    for(int i=2;i<=n;i++){
        pos=(op[i-1].s+op[i-1].w+pos)-op[i].s;
        ans=max(ans,pos);
    }
    printf("%d\n",ans);
    return 0;
}
听说是luogu原题,没找着
答案具有单调性,可以二分答案,判断的时候以行和列为单位判就可以了
码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=1010;
ll mapp[N][N];
ll n,m,ans=0,maxx=0,minn=0x3f3f3f3ff,s[N];
bool vis[N][N];//一列一行
inline ll read(){
    ll x=0,y=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) y=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar();
    return x*y;
}
bool check(ll x){//我就这一个地方没开ll,卡掉50pts
    memset(vis,false,sizeof(vis));
    int top;
    for(int i=1;i<=n;i++){
        top=0;
        for(int j=1;j<=m;j++) if(mapp[i][j]>=x) s[top++]=j;
        for(int j=0;j<top;j++){
            for(int k=j+1;k<top;k++){
                if(vis[s[j]][s[k]]) return true;
                vis[s[j]][s[k]]=true;
            }
        }
    }
    return false;
}
ll bisearch(){
    ll l=minn,r=maxx;
    while(l<r){
        ll mid=(l+r+1)>>1;
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    return l;
}
int main(){
    n=read(),m=read();
    if(n<2||m<2) cout<<0<<endl,exit(0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            mapp[i][j]=read(),maxx=max(maxx,mapp[i][j]),minn=min(minn,mapp[i][j]);
    printf("%lld\n",bisearch());
    
    return 0;
}
这个词我会(
6e11可过
题解给的是DP做法\(O(n^4)\)
我的是3e8过了
考虑维护两个四维数组,先定左上点求最大,再以左上点为转移求答案,式子在代码里面
题解:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=55;
int dp[N][N][N][N],n,m,s[N][N],q;
int f[N][N][N][N];
inline int read(){
    int x=0,y=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) y=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar();
    return x*y;
}
int main(){
    n=read(),m=read(),q=read();
    memset(f,0,sizeof f);
    memset(dp,0,sizeof dp);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) s[i][j]=read();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            s[i][j]+=(s[i-1][j]+s[i][j-1]-s[i-1][j-1]);
        }
    }//二维前缀和
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int l=1;l<=n;l++){
                for(int r=1;r<=n;r++){
                  //这里
                    dp[i][j][l][r]=s[l][r]-s[i-1][r]-s[l][j-1]+s[i-1][j-1];
                    if(l-1>=i) dp[i][j][l][r]=max(dp[i][j][l][r],dp[i][j][l-1][r]);
                    if(r-1>=j) dp[i][j][l][r]=max(dp[i][j][l][r],dp[i][j][l][r-1]);
                  //这里
                }
            }
        }
    }
    for(int i=n;i>=1;i--){
        for(int j=n;j>=1;j--){
            for(int l=1;l<=n;l++){
                for(int r=1;r<=n;r++){
                  //这里
                    f[i][j][l][r]=dp[i][j][l][r];
                    if(i+1<=l) f[i][j][l][r]=max(f[i][j][l][r],f[i+1][j][l][r]);
                    if(j+1<=r) f[i][j][l][r]=max(f[i][j][l][r],f[i][j+1][l][r]);
                  //这里
                }
            }
        }
    }
    for(int i=1;i<=q;i++){
        int a,b,c,d;
        a=read(),b=read(),c=read(),d=read();
        printf("%d\n",f[a][b][c][d]);
    }
    
    return 0;
}
我哒:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=60;
int m,n,q,s[N][N];
struct query{
    int x1,y1,x2,y2,ans;
}qo[100010];
inline int read(){
    int x=0,y=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) y=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar();
    return x*y;
}
void work(){
    int f[N][N];
    for(int d=1;d<=q;d++){
        for(int i=qo[d].y1;i<=qo[d].y2;i++)
            for(int j=i;j<=qo[d].y2;j++){
                    int sum=0;
                    for(int k=qo[d].x1;k<=qo[d].x2;k++){
                    if(sum>0) sum+=s[k][j]-s[k][i-1];
                    else sum=s[k][j]-s[k][i-1];
                    qo[d].ans=max(qo[d].ans,sum);
                }
            }
    }
}
int main(){
    n=read(),m=read(),q=read();
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) s[i][j]=read(),s[i][j]+=s[i][j-1];
    for(int i=1;i<=q;i++) qo[i].x1=read(),qo[i].y1=read(),qo[i].x2=read(),qo[i].y2=read(),qo[i].ans=-INF;
    work();
    for(int i=1;i<=q;i++) printf("%d\n",qo[i].ans);
    return 0;
}
离谱的搜索,本来看着像多背包,但是数据不对劲而且价值都是1,以为搜索拿不了多少分然后就没写,然后XiEn1847随机化贪心拿了50pts,Orz
搜索好题,几乎所有剪枝都用上了
答案具有单调性可以二分答案
直接DFS上
剪枝:
码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=900010;
int n,m,mon[N],w[N],smon=0,l,r,sw[N];
bool cmp(int a,int b){
    return a>b;
}
inline int read(){
    int x=0,y=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) y=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar();
    return x*y;
}
bool dfs(int x,int pre,int v,int tot){
    if(!x) return 1;
    if(smon-v<sw[tot]) return 0;
    int tmp=((w[x]==w[x+1])?pre:1);
    for(int i=tmp;i<=n;i++){
        if(mon[i]>=w[x]){
            mon[i]-=w[x];
            int t=((mon[i]<w[1])?mon[i]:0);
            if(dfs(x-1,i,v+t,tot)){
                mon[i]+=w[x];
                return 1;
            }
            mon[i]+=w[x];
        }
    }
    return 0;
}
bool check(int x){
    return dfs(x,1,0,x);
}
int main(){
    n=read();
    for(int i=1;i<=n;i++) mon[i]=read(),smon+=mon[i];
    m=read();
    for(int i=1;i<=m;i++) w[i]=read();
    sort(w+1,w+1+m);
    sort(mon+1,mon+n+1,cmp);
    
    for(int i=1;i<=m;i++) sw[i]=sw[i-1]+w[i];
    l=0,r=m;
    while(l<r){
        int mid=(l+r+1)>>1;
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    printf("%d\n",l);
    
    return 0;
}
原文:https://www.cnblogs.com/wsyunine/p/14869738.html