[Offer收割机]编程练习赛1

前言

这次应该算是去年放假以后第一次写代码吧,感觉脑子还是有点秀逗的,这次的题目感觉确实都是水题,居然有一题还没写出来,好像第四题做的时候没看到剩下来的70%的数据,以为是对语言70%的数据,再次表示读题很重要!!!(想起去年的EC真是心痛)。

只是试试图片而已

分析

  1. 第一题,暴力模拟,只需要把所有满足情况的 9 宫格表示出来就好了,然后暴力判断给出的图案和几个满足条件的9宫格一样。
  2. 第二题,暴力,使用一个数据结构(我用的是priority_queue)来模拟整个过程就好了,二分答案,搞定。
  3. 第三题,暴力每一层的情况,发现直接就转化成了一个完全背包问题,转移方程: dp[v]=min(dp[v],dp[vb[i]]+a[i]) ,复杂度为 o(nmK)
  4. 第四题,(两个数组的)正序(乘积和)>乱序>逆序。这样如果确定了那些位置放对空,哪些位置放对舰,就只有一种排列了。这个时候就可以暴力 16 个位置放了什么。一共个就是 216 种可能,然后每一种情况进行判断就好了。复杂度是 o(nm2nm)

代码

只贴一下第四题的代码,感觉第四题被我写得很烂,写了两遍一样的代码。写完以后想想完全没有必要的,看来还是要多想想再写。

#include <bits/stdc++.h>

using namespace std;

typedef pair <int,int>  PII;
#define FOR(i,x,y)  for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)
#define mp  make_pair 
#define fi  first
#define se  second

const int maxn = 1000;
int n,m,t,S;
int a[4][4],p[maxn],q[maxn],lep,leq;

bool cmp(int a,int b)   {return a > b;}
bool cmp_PII(PII a,PII b)   {return a.fi == b.fi ? a.se < b.se : a.fi > b.fi;}

void work(){
    sort(p,p+lep,cmp);  sort(q,q+leq,cmp);  
    int ans = -1;
    int cnt = n*m;  int maxp = 1<<cnt;
    FOR(i,0,maxp){
        PII b[16],c[16];
        int leb = 0,lec = 0;
        FOR(j,0,cnt){
            int x = j/m ,y = j%m;
            if(i & (1<<j))  b[leb++] = mp(a[x][y],j);
            else    c[lec++] = mp(a[x][y],j);
        }
        sort(b,b+leb,cmp_PII);  sort(c,c+lec,cmp_PII);
        int lebp = min(leb,lep),sump = 0;
        FOR(j,0,lebp)   sump += b[j].fi*p[j];
        if(sump < S)    continue;
        int lecq = min(lec,leq),sumq = 0;
        FOR(j,0,lecq)   sumq += c[j].fi*q[j];
        ans = max(ans,sumq);
    }
    if(ans == -1)   {printf("Not Exist\n");return;}
    if(ans == 0)    {printf("0\nNo\n");return;}
    printf("%d\n",ans);
    bool flag = false;
    FOR(i,0,maxp){
        PII b[16],c[16];
        int leb = 0,lec = 0;
        FOR(j,0,cnt){
            int x = j/m ,y = j%m;
            if(i & (1<<j))  b[leb++] = mp(a[x][y],j);
            else    c[lec++] = mp(a[x][y],j);
        }
        sort(b,b+leb,cmp_PII);  sort(c,c+lec,cmp_PII);
        int lebp = min(leb,lep),sump = 0;
        FOR(j,0,lebp)   sump += b[j].fi*p[j];
        if(sump < S)    continue;
        int lecq = min(lec,leq),sumq = 0;
        FOR(j,0,lecq)   sumq += c[j].fi*q[j];
        if(ans == sumq){
            bool vis[4];    FOR(j,0,n)  vis[j] = false;
            FOR(j,0,lecq)   vis[c[j].se/m] = true;
            bool f = true;
            FOR(j,0,n)  if(!vis[j]) {f = false;break;}
            if(f)   {flag = true;break;}
        }
    }
    if(flag)    printf("Yes\n");
    else    printf("No\n");
    return;
}

int main(){
    int Q;  scanf("%d",&Q);
    while(Q--){
        scanf("%d%d%d%d",&n,&m,&t,&S);
        FOR(i,0,n)  FOR(j,0,m)  scanf("%d",&a[i][j]);
        int u;  lep = leq = 0;
        FOR(i,0,t)  scanf("%d",&u),p[lep++] = u;    
        FOR(i,0,t)  scanf("%d",&u),q[leq++] = u;
        work();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值