6.9模拟赛

6.9 模拟赛

T1 叠虚

并不知道叠虚是什么意思,有人来教教吗/kk

没想到解法,只觉得这题搜索和DP都做不了,所以用堆维护,贪心了一下,没证明,贪错了(((

正解给的是按力量值s和重量值w之和从小到大排序,排完序之后的序列就是从上至下的叠放顺序

证明:

\[取原序列中某连续两人的风险值r_i和r_{i+1}\\ 有r_i=\sum_{j=1}^{i-1}w_j-s_i\\r_{i+1}=\sum_{j=1}^iw_j-s_{i+1}\\ 令A=\sum_{j=1}^{i-1}w_j\\ 则r_i=A-s_i\\r_{i+1}=A+w_i-s_{i+1}\\ 若将两人调换位置,两人的风险值为r_i'和r’_{i+1}\\ 有r'_{i+1}=A-s_{i+1}\\r'_i=A+w_{i+1}-s_{i}\\ 假设s_i+w_i\geq s_{i+1}+w_{i+1}\\ 即w_i-s_{i+1}\geq w_{i+1}-s_i\\ 所以r_{i+1}\geq r'_i\\ 又因为r_i\leq r'_i,r_{i+1}\geq r'_{i+1}\\ 所以r_{i+1}\geq r_i\\ 调换前,r_{i+1}为最大风险值\\ 调换后,r'_i和r'_{i+1}都比r_{i+1}小\\ 显然调换后序列更优 \]

码:(原来错误的码改的,丑死了)

#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;
}

T2 盖房子

听说是luogu原题,没找着

答案具有单调性,可以二分答案,判断的时候以行和列为单位判就可以了

开longlong麻烦开全谢谢

码:

#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;
}

T3 矿脉

这个词我会(

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;
}

T4 食堂承包

离谱的搜索,本来看着像多背包,但是数据不对劲而且价值都是1,以为搜索拿不了多少分然后就没写,然后XiEn1847随机化贪心拿了50pts,Orz

搜索好题,几乎所有剪枝都用上了

答案具有单调性可以二分答案

直接DFS上

剪枝:

  1. 对于一个二分出来的答案,我们选择体积更小的装入
  2. 二分上下界:上界:保证总容量能够包了体积最小的r个物品 下界:保证体积最小的l个物品装进容量最大的l个背包里
  3. 把价格相同的餐厅一起考虑
  4. 各种可行性剪枝

码:

#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;
}
posted @ 2021-06-10 09:12  wsy_jim  阅读(52)  评论(0编辑  收藏  举报