【NOIP2017】Day4

Solution

T1:首先可以想到分成两组暴搜+剪枝得到所有可能,然后meeting in middle,尴尬的是时间与空间,时间从2s—>5s—>12s(评测时才改的,考试时只到5s),对于时间12s可以直接快排, 22667000000 512M可以开两个刚刚好,考场上我以为快排过不了,就写了个基数排序,结果要开三个数组,空间炸了……标称方法是一边 224 记到数组,之后剩下的枚举也可以过,不过都是10s左右,对于空间上ljn大佬的方法是拿出4个来,剩下的 225 够开,剩下的4个 24 枚举即可,加上我的基数排序最慢的点2s也过了。
T2:
网上有题解:
http://blog.csdn.net/longyuepeng/article/details/38521877
http://blog.csdn.net/ypxrain/article/details/72864491
T3:类似POJ消防站一题,我在灰色的果实一题也写过,不过老师好像有另外的解法:f[i][j][k]表示i的水库距离为j,k表示是否在子树内。其实我也不会。

CODE

T1

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=34000000;
int a[100],b[100],c[2],cnt[1<<17];
int x[MAXN],y[MAXN],z[MAXN];
int cnta,cntb,cntx,cnty,W,n,ans=0;

void dfs1(int k,int sum)
{
    if (sum>W) return;
    if (k>cnta)
    {
        x[++cntx]=sum;
        return;
    }
    dfs1(k+1,sum);
    dfs1(k+1,sum+a[k]);
}
void dfs2(int k,int sum)
{
    if (sum>W) return;
    if (k>cntb)
    {
        y[++cnty]=sum;
        return;
    }
    dfs2(k+1,sum);
    dfs2(k+1,sum+b[k]);
}
void my_sort(int *x,const int &cntx)
{
    //first;
    memset(cnt,0,sizeof(cnt));
    int bit=(1<<15)-1;
    for (int i=1;i<=cntx;i++)
        cnt[x[i]&bit]++;
    for (int i=1;i<=bit;i++)
        cnt[i]=cnt[i-1]+cnt[i];
    for (int i=1;i<=cntx;i++)
        z[cnt[x[i]&bit]]=x[i],cnt[x[i]&bit]--;
    //second;
    memset(cnt,0,sizeof(cnt));
    for (int i=1;i<=cntx;i++)
        cnt[z[i]>>15]++;
    for (int i=1,p=1<<16;i<=p;i++)
        cnt[i]=cnt[i-1]+cnt[i];
    for (int i=cntx;i>=1;i--)
        x[cnt[z[i]>>15]]=z[i],cnt[z[i]>>15]--;
}
void solve(int p)
{
    int j=cnty;
    for (int i=1;i<=cntx && j;i++)
    {
        while (j && x[i]+y[j]+p>W) j--;
        if (j) ans=max(ans,x[i]+y[j]+p);        
    }
}
int main()
{
    freopen("brick.in","r",stdin);
    freopen("brick.out","w",stdout);
    scanf("%d%d",&W,&n);
    cnta=n/2-1; cntb=n-n/2-1;
    for (int i=1;i<=cnta;i++)
        scanf("%d",&a[i]);
    for (int i=1;i<=cntb;i++)
        scanf("%d",&b[i]);
    scanf("%d%d",&c[0],&c[1]);
    dfs1(1,0);
    dfs2(1,0);
    my_sort(x,cntx);
    my_sort(y,cnty);
    //sort(x+1,x+1+cntx);
    //sort(y+1,y+1+cnty);   
    cntx=unique(x+1,x+1+cntx)-x-1;
    cnty=unique(y+1,y+1+cnty)-y-1;
    solve(0);
    solve(c[0]);
    solve(c[1]);
    solve(c[0]+c[1]);
    printf("%d\n",ans); 
    return 0;
}

T2

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int MAXN=50050;
int n,Y,u;
int w[MAXN],v[MAXN],h[MAXN];
double ans;

struct node{
    double t;
    int id;
    friend bool operator < (const node &x,const node &y)
    {
        return x.t>y.t;
    }
};
priority_queue<node>Q;
inline double dis(int x,int y)
{return sqrt(x*x+y*y);}

int main()
{
    freopen("river.in","r",stdin);
    freopen("river.out","w",stdout); 
    scanf("%d%d%d",&n,&Y,&u);
    for (int i=1;i<=n;i++)
        scanf("%d",&w[i]);
    for (int i=1;i<=n;i++)
        scanf("%d",&v[i]);
    for (int i=1;i<=n;i++)
        ans+=w[i]/(double)v[i];
    for (int i=1;i<=n;i++)
    {
        double dd=dis(1,w[i])-w[i];
        Q.push((node){dd/v[i],i});
    }
    Q.push((node){1/(double)u,0});
    for (int i=1;i<=Y;i++)
    {
        int id=Q.top().id;
        ans+=Q.top().t;
        if (!id) continue;
        Q.pop();
        h[id]++;
        double dd=dis(h[id]+1,w[id])-dis(h[id],w[id]);
        Q.push((node){dd/v[id],id});        
    }
    printf("%.4f\n",ans);
    return 0;
}

T3

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=1005;
int dis[MAXN][MAXN],dp[MAXN][MAXN],best[MAXN];
int c[MAXN],t[MAXN],Head[MAXN];
int n,tot=0,ans=0x3f3f3f3f;

struct Edge{
    int v,next;
}edge[MAXN*2];

void add_edge(int x,int y)
{
    edge[++tot]=(Edge){y,Head[x]};
    Head[x]=tot;
}
void dfs_dis(int u,int pre,int rt)
{
    for (int i=Head[u];i;i=edge[i].next)
    {
        int v=edge[i].v;
        if (v==pre) continue;
        dis[rt][v]=dis[rt][u]+1;
        dfs_dis(v,u,rt);    
    }
}
void dfs(int u,int pre)
{
    for (int i=Head[u];i;i=edge[i].next)
    {
        int v=edge[i].v;
        if (v==pre) continue;
        dfs(v,u);
    }
    for (int w=1;w<=n;w++)
    {
        dp[u][w]=c[w]+t[dis[w][u]];
        for (int i=Head[u];i;i=edge[i].next)
        {
            int v=edge[i].v;
            if (v==pre) continue;
            dp[u][w]+=min(dp[v][w]-c[w],best[v]);   
        }
        best[u]=min(best[u],dp[u][w]);
    }   
}
int main()
{
    freopen("reservoir.in","r",stdin);
    freopen("reservoir.out","w",stdout);
    scanf("%d",&n); 
    for (int i=1;i<=n;i++)
        scanf("%d",&c[i]);
    for (int i=1;i<=n;i++)
        scanf("%d",&t[i]);
    for (int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add_edge(x,y); add_edge(y,x);       
    }
    for (int i=1;i<=n;i++) dfs_dis(i,0,i);
    memset(dp,0x3f,sizeof(dp));
    memset(best,0x3f,sizeof(best));
    dfs(1,0);
    cout<<best[1]<<endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值