9.14 模拟赛

模拟赛第三弹~

 

T1

题意:给你一个数列,要求删掉任意一种整数,使得剩下的新数列中连续的相等的数最多

例如 2 7 3 7 7 3 3 7 7 5 7,删掉3以后剩的7有四个连续的,最多

 

思路:暴力枚举去掉哪个......这算是一道水题吧

 

代码丢了...... TAT

 

T2

题意:有n本书,每本书有宽度和高度。现在你有无数个书架,每个书架的宽度为w,高度由最高的书决定

问在书本按顺序放的情况下,总的书架高度最小是多少

 

思路:dp,dp[i]表示做到第i本书时的最小高度和。

每次先找到能以编号j的书开始,编号i结束的一批书能放在同一个书柜里时,j的最小值,

然后枚举j到i-1,查找这一批书的最大值,dp[i]=min(dp[j]+max_height(h[j]~h[i]))

宽度前缀和,高度线段树

 

代码丢了*2

 

T3

题意:有一头牛,坐标(bx,by),n个柱子,横坐标都是cx,纵坐标是cy[i]

现在从牛身上开始有m段绳子,每个绳子有起点和终点坐标,绕在牛身上成为一圈

问最少拔掉几个柱子,能让牛逃走

 

思路:非常规题目,第一眼以为wind算法......

然而正解到现在都没看懂,挖坑*1

 

T4

题意:有n头牛(n<=20),每个牛有产奶量a[i],现在让你在所有牛中选出一部分,使得这些牛可以分成产奶量相同的两组

问:一共有多少种选择方法

 

思路:折半搜索(meet in the middle),先把两边的所有方法搜出来(状压方法表示),然后双指针维护,每次用位运算查看一下当前的合法状态是否已经算过

对于左边(i=1~n/2)和右边(i=n~n/2+1)的dfs,每次有三种情况:放在A组,放在B组,不选

这样最后只要看左边和右边dfs得出的所有情况里面,| Ai-Bi | (left) ==| Ai-Bi | (right) 的有多少组(不重复的)

 

代码(终于找到了!!!!):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{
    int s,x,next;
}l[1100010],r[1100010];
int n,a[30],firstl[10010],firstr[10010],totl,totr;
void dfs1(int k,int sum,int s){
    if(k==n/2+1){
        if(sum>=0){
            l[++totl].s=s;l[totl].x=sum;
            l[totl].next=firstl[s];firstl[s]=totl;
        }
        return;
    }
    dfs1(k+1,sum,s);
    dfs1(k+1,sum+a[k],s|(1<<(k-1)));
    dfs1(k+1,sum-a[k],s|(1<<(k-1)));
}
void dfs2(int k,int sum,int s){
    if(k==n/2){
        if(sum>=0){
            r[++totr].s=s;r[totr].x=sum;
            r[totr].next=firstr[s];firstr[s]=totr;
        } 
        return;
    }
    dfs2(k-1,sum,s);
    dfs2(k-1,sum+a[k],s|(1<<(n-k)));
    dfs2(k-1,sum-a[k],s|(1<<(n-k)));
}
bool vis[5001000]={0};
bool cmp(node x,node y){
    return x.x<y.x;
}
int main(){
    int i,p1,p2,tmp1,tmp2,ans=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++) scanf("%d",&a[i]);
    dfs1(1,0,0);dfs2(n,0,0);
    sort(l+1,l+totl+1,cmp);sort(r+1,r+totr+1,cmp);
    p1=1;p2=1;
    while(p1<=totl&&p2<=totr){
        if(l[p1].x>r[p2].x){
            p2++;continue;
        }
        if(l[p1].x<r[p2].x){
            p1++;continue;
        }
        tmp1=p1;tmp2=p2;
        while(l[p1].x==l[tmp1].x) p1++;
        while(r[p2].x==r[tmp2].x){
            for(i=tmp1;i<p1;i++){
                if(!vis[((r[p2].s)<<(n/2))|l[i].s]){
                    ans++;vis[((r[p2].s)<<(n/2))|l[i].s]=1;
                }
            }
            p2++;
        }
    }
    printf("%d",ans-1);
}

 

总分:240+,自我感觉良好ing

然而对于代码实现(第四题)还是要加强啊......

posted @ 2017-09-20 21:53  dedicatus545  阅读(123)  评论(0编辑  收藏  举报