码迷,mamicode.com
首页 > 其他好文 > 详细

[USACO 2018 Open Gold] Tutorial

时间:2018-09-09 21:07:21      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:splay   alt   最大的   blog   lap   好的   one   tps   csdn   

Link:

传送门

A:

对于每一条分割线,设本不应在其左侧的个数为$x$

重点要发现每次一来一回的操作恰好会将一对分别应在左/右侧的一个数从右/左移过去

这样就转直接用树状数组求出最大的$x$即可

技术分享图片
#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=1e5+10;
//res至少为1 
int n,bit[MAXN],res=1;P dat[MAXN];

void Update(int x)
{while(x<=n) bit[x]++,x+=x&(-x);}
int Query(int x)
{
    int ret=0;
    while(x) ret+=bit[x],x-=x&(-x);
    return ret;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&dat[i].X),dat[i].Y=i;
    sort(dat+1,dat+n+1);
    
    for(int i=1;i<n;i++)
        Update(dat[i].Y),res=max(res,i-Query(i));
    printf("%d",res);
    return 0;
}
Problem A

冒泡排序相关题多考虑数与数相对位置以及每个数应在的位置

 

B:

发现答案具有单调性后首先想到二分答案或是直接枚举

由于不用重复建图,直接枚举看起来能更快一些,不过好像并不能在线$O(logn)$判断是否出现了环……

(按照杨主力的指示还是在google上搜到了论文,不过并不打算学传送门

剩下就是优先队列套拓扑排序就行了

技术分享图片
#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
#define pb push_back
typedef long long ll;
typedef pair<int,int> P;
typedef double db;
const int MAXN=1e5+10;
vector<int> dat[MAXN];
struct edge{int nxt,to;}e[MAXN<<2];
int n,m,num,x,head[MAXN],res[MAXN],in[MAXN],tot;

void add_edge(int x,int y)
{e[++tot].nxt=head[x];e[tot].to=y;head[x]=tot;}
void build(int x)
{
    tot=0;
    memset(in,0,sizeof(in));
    memset(head,0,sizeof(head));
    for(int i=1;i<=x;i++)
        for(int j=0;j<dat[i].size()-1;j++)
            add_edge(dat[i][j],dat[i][j+1]),in[dat[i][j+1]]++;
}
bool check()
{
    int sz=0;
    priority_queue<int,vector<int>,greater<int> > q;
    for(int i=1;i<=n;i++)
        if(!in[i]) q.push(i);
    while(!q.empty())
    {
        int t=q.top();q.pop();
        res[++sz]=t;
        for(int i=head[t];i;i=e[i].nxt)
        {
            in[e[i].to]--;
            if(!in[e[i].to]) q.push(e[i].to);
        }
    }
    return (sz==n);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&num);
        for(int j=1;j<=num;j++)
            scanf("%d",&x),dat[i].pb(x);
    }
    
    int l=1,r=m;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        build(mid);
        if(check()) l=mid+1;
        else r=mid-1;
    }
    build(r);check();
    for(int i=1;i<=n;i++)
        printf("%d ",res[i]);
    return 0;
}
Problem B

 

C:

明显0/1分数规划,每次$dp$找当前重量大于等于$m$的最大权值和即可

一篇很好的博客,图解0/1分数规划:传送门

顺便学了下$Dinkelbach$算法,发现就是每次找到最大值时直接跳到该方案的零点处

直到该方案的零点为当前$x$下的最大值时停止即可

技术分享图片
#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second 
typedef long long ll;
typedef pair<int,int> P;
typedef double db;
const int MAXN=1e5+10;
int n,m,w[MAXN],t[MAXN];
db l,r,a[MAXN],dp[MAXN];

bool check(db x)
{
    for(int i=1;i<=n;i++)
        a[i]=t[i]-1.0*x*w[i];
    for(int i=1;i<=m;i++) dp[i]=-1e9;    
    
    for(int i=1;i<=n;i++)
        for(int j=m;j>=0;j--)
            dp[min(m,j+w[i])]=max(dp[min(m,j+w[i])],dp[j]+a[i]);
    return dp[m]>=0;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&w[i],&t[i]),r+=t[i];
    
    while(fabs(l-r)>1e-6)
    {
        db mid=(l+r)/2.0;
        if(check(mid)) l=mid;
        else r=mid;
    }
    printf("%d",int((l+r)*500));
    return 0;
}
Problem C

 

[USACO 2018 Open Gold] Tutorial

标签:splay   alt   最大的   blog   lap   好的   one   tps   csdn   

原文地址:https://www.cnblogs.com/newera/p/9603979.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!