0419

贪心问题

区间找点

喷水装置(一)

喷水装置(二)

Rader

buying feed

同样是先输入组数

然后输入要买K磅,从0点出发终点为e,n家商店

n行输入,这些商店的坐标,最多能买进多少磅种子,每磅Ci元

在每个商店买一磅并到达终点的花费作为单价(c[i]+(E-x[i])),不用考虑距离只用贪心选单价小的即可

2 5 3

3 1 2  单价为(5-3)+2=4

4 1 2              (5-4)+2=3

1 1 1 (5-1)+1=5

输出  7

至于DP加单调队列优化 ,

滑雪

---------------------

color the fence

田忌赛马

寻找最大数

过河问题

独木舟上的旅行

Strategic Game

3 域的说明: 用yes,no分别表示某节点上放置士兵与否守住整棵子树的最小需求量; 用flag标记某节点的no值是否有效,即在该点不放置士兵时no值是否可以取道,一个节点的flag只是标记no的,与yes无关,且由其子节点决定,如果该节点的no取的子节点的值中有一个yes,即有一个子节点上放置有士兵,则flag=1; 守住所有的边(本题要求): 状态转移方程: dp[father].yes= (min (dp[child].yes, dp[child].no) 之和); 在某节点上放置士兵,则该节点的子节点是否放置士兵都无所谓,取更小者即可; dp[father].no= dp[child].yes 之和; 不在某节点上放置士兵,则该节点的子节点必须放置士兵; 守住所有的点(不是这一题,自己推的,也不知道是否正确,以后应该用得到): 状态转移方程: dp[father].yes= ( min(dp[child].yes,dp[child].no) 之和); 在某节点上放置士兵,则该节点的子节点是否放置士兵都无所谓,取更小者即可; if(dp[child].yes<=dp[child].no) dp[father].no+= dp[child].yes, dp[father].flag=1; 如果一个子节点上放置士兵时的最优解比不放时的还优,那么自然取放置士兵,同时因有一个子节点放置了士兵,则父节点就可以不放,标记flag=1; else{ if(t[child].flag) t[x].no+= t[child].no; //某个子节点允许不放士兵,父节点依旧加,只是不标记而已,因为父节点可以通过其他的子节点上放置士兵来守住该父节点; else t[x].no+= t[child].yes, t[x].flag=1;//某子节点不允许不放士兵,则必须放一个,同时因为放了,父节点可以不放,标记flag=1; } 其中树的构造,我是开struct的,和之前的一样(见我的pku3342里面有关于构造树的详细说明),其实也可以用vector的; 其实这题的另一做法是二分图,用到里面的一个结论,什么点最大覆盖的,可以百度,但树形DP的代码是运行最快的,二分图很慢;

 
4 
/*2011-03-02 15:47:07 Accepted 1054 140MS 312K 1313 B C++*/ #include<stdio.h> #include<string.h> #include<iostream> using namespace std; struct Node{ 
    int father,brother,child;     int yes,no;      void init(){ 
        father=brother=child=0;         yes=1,no=0;     } }t[1505]; void DFS(int x){     int child=t[x].child;     while(child){         DFS(child); 
        t[x].yes+= min(t[child].yes,t[child].no);         t[x].no+= t[child].yes;         child= t[child].brother;     } }         int main() { 
    int n,i,j,cnt,root;     bool use[1505]; 
    while(scanf("%d",&n)!=EOF)     { 
        memset(use,0,sizeof(use));         int Root;         for(i=1;i<=n;i++){ 



 


 5 
            scanf("%d:(%d)",&root,&cnt), root++;             if(i==1) Root=root;             if(!use[root]){                 t[root].init();                 use[root]=1;             }                    while(cnt--){ 
                scanf("%d",&j), j++;                 if(!use[j]){                     t[j].init();                     use[j]=1;                 } 
                t[j].brother=t[root].child;                 t[j].father= root;                 t[root].child= j;             }         } 
        DFS(Root);    
        printf("%d\n",min(t[Root].yes,t[Root].no));      } } 
农民木板

#include <iostream>  
#include <cstring>  
#include <stdlib.h>  
#include <stdio.h>  
using namespace std;  
int a[20010];  
int cmp(const void *e,const void *f)  
{  
  return (*(int *)e-*(int *)f);  
}  
int main()  
{  
    int i,j,n,m,t;  
    __int64 sum,s;  
    scanf("%d",&n);  
    for(i=0;i<=n-1;i++)  
    {  
        scanf("%d",&a[i]);  
    }  
    qsort(a,n,sizeof(a[0]),cmp);  
    sum=0;  
    for(i=1;i<=n-1;i++)  
    {  
        s=(a[i-1]+a[i]);  
        sum+=s;  
        for(j=i+1;j<=n-1;j++)  
        {  
            if(a[j]<s)  
            {  
                a[j-1]=a[j];  
            }else  
            {  
                break;  
            }  
        }  
        a[j-1]=s;  
    }  
    printf("%I64d/n",sum);  
    return 0;  
}  

线段树

市长的海报

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define L(rt) (rt<<1)
#define R(rt) (rt<<1|1)
using namespace std;

const int maxn = 100005;
const int INF = 1000000000;

struct node
{
    int l, r, color;
} tree[4 * maxn];
int n;
int hash[10000005], a[10005], b[10005];
bool vis[10005];
void build(int l, int r, int rt)
{
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].color = 0;
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(l, mid, L(rt));
    build(mid + 1, r, R(rt));
}
void update(int l, int r, int rt, int val)
{
    if(tree[rt].l == l && tree[rt].r == r)
    {
        tree[rt].color = val;
        return;
    }
    if(tree[rt].color == val) return;
    if(tree[rt].color)
    {
        tree[L(rt)].color = tree[R(rt)].color = tree[rt].color;
        tree[rt].color = 0;
    }
    int mid = (tree[rt].l + tree[rt].r) >> 1;
    if(r <= mid) update(l, r, L(rt), val);
    else if(l > mid) update(l, r, R(rt), val);
    else
    {
        update(l, mid, L(rt), val);
        update(mid + 1, r, R(rt), val);
    }
}
void query(int l, int r, int rt)
{
    if(tree[rt].color)
    {
        vis[tree[rt].color] = true;
        return;
    }
    if(r <= tree[L(rt)].r) query(l, r, L(rt));
    else if(l >= tree[R(rt)].l) query(l, r, R(rt));
    else query(l, tree[L(rt)].r, L(rt)), query(tree[R(rt)].l, r, R(rt));
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        build(1, maxn, 1);
        memset(hash, 0, sizeof(hash));
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d", &a[i], &b[i]);
            hash[a[i]] = hash[b[i]] = 1;
        }
        int cnt = 0;
        for(int i = 1; i <= 10000000; i++)
            if(hash[i]) hash[i] = ++cnt;
        for(int i = 1; i <= n; i++)
            update(hash[a[i]], hash[b[i]], 1, i);
        memset(vis, false, sizeof(vis));
        query(1, cnt, 1);
        int ans = 0;
        for(int i = 1; i <= n; i++)
            if(vis[i]) ans++;
        printf("%d\n", ans);
    }
    return 0;
}

有n个数,进行n次操作,每次操作有两个数pos, ans。pos的意思是把ans放到第pos 位置的后面,pos后面的数就往后推一位。最后输出每个位置的ans。
思路:根据题 目可知,最后插入的位置的数才是最终不变的数,所以可以从最后的输入作第1个放入,依此类推,倒插入。在插入时也有一定的技术,首先创建一棵空线段树时,每个节点记录当前范围内有多少个空位置。在插入时,要注意,一个数放入之后那么这个位置就不用管了,那么树中所有的空位置就是余下的数所对应的位置,也就是把余下的数又可以看作是一个新的集合。那么每次插入都是当前集合的第1次放。
#include<stdio.h>

#define Lson(n)  (n<<1)
#define Rson(n)  (n<<1|1)
#define MID(a,b) (a+b>>1)

const int MAXN=200005;

int N,P[MAXN],V[MAXN],Loc,Ans[MAXN],SegmTree[MAXN<<2];

void Build(int L,int R,int N)
{
    SegmTree[N]=R-L+1;
    if(L!=R)
    {
        int M=MID(L,R);
        Build(L,M,Lson(N));
        Build(M+1,R,Rson(N));
    }
}

void Insert(int Pos,int L,int R,int N)
{
    --SegmTree[N];
    if(L==R)
    {
        Loc=L;
    }
    else
    {
        int M=MID(L,R);
        if(SegmTree[Lson(N)]>Pos) Insert(Pos,L,M,Lson(N));
        else Insert(Pos-SegmTree[Lson(N)],M+1,R,Rson(N));
    }
}

int main()
{
    while(scanf("%d",&N)==1)
    {
        Build(0,N-1,1);
        for(int i=0;i<N;++i)
        {
            scanf("%d%d",&P[i],&V[i]);
        }
        for(int i=N-1;i>=0;--i)
        {
            Insert(P[i],0,N-1,1);
            Ans[Loc]=V[i];
        }
        for(int i=0;i<N;++i)
        {
            printf("%d%c",Ans[i],i+1<N?' ':'\n');
        }
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值