百度之星初赛b

hdu6114

推一下发现是求c(n,m),范围很小直接预处理递推

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int mod=1e9+7;
 4 const int maxn=1008;
 5 int c[maxn][maxn];
 6 void init()
 7 {
 8     memset(c,0,sizeof(c));
 9     c[0][0]=1;
10     for(int i=1;i<=1000;i++)
11         for(int j=0;j<=i;j++)
12             c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
13 }
14 int main()
15 {
16     int t;
17     scanf("%d",&t);
18     init();
19     int n,m;
20     while(t--)
21     {
22         scanf("%d%d",&n,&m);
23         if(n>m)
24         {
25             int temp=n;
26             n=m;
27             m=temp;
28         }
29         printf("%d\n",c[m][n]);
30     }
31     return 0;
32  } 

 

 hdu6115

可以转化为求lca问题。(为什么我做过的lca题时限都这么鬼畜呢,我以后永远选择树上倍增)

lca:求两个节点的最近公共祖先,一般有如下三种方法:

树上倍增算法:先将两个点移到同一高度,再让他们一起往上爬,直到相遇。对爬的过程进行了优化:建立一系列向上爬2^0高度,2^1,...2^n高度的边,使得点可以沿这些边加速爬来接近目标。可以用求树的重心法优化

tarjan算法:将所有询问离线处理,通过花式标记+简单并查集处理(个人认为这个方法是真的鬼畜,因为标记不少,又要维护集合,使得代码实际跑的速度比理论复杂度要大,常常出现O(n)跑不过O(nlogn)的情况,表示束手无策)

树刨+rmq:按照dfs序处理一条2n长的链,使得链中公共祖先一定在任意两个子节点的中间。然后rmq维护之,查询其中深度最小的点(表示非常蛋疼)

总之求lca是不难的,难点就在卡时间。就算用到了上述算法,但实现不够优秀,一样会t一脸。也不能说是被故意卡掉的,实在是rmq的测试数据都太大了,点多边多询问多,不小心可能连标程都卡掉这样子。。。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int N = 100010, INF = 0x3f3f3f3f;
 6 struct edge
 7 {
 8     int to, cost, next;
 9 }g[N*2];
10 int cnt, head[N];
11 int dep[N];
12 int dis[N], p[N][20+5];
13 bool vis[N];
14 
15 int n, m;
16 vector<int> vec[N];
17 void init()
18 {
19     cnt=0;
20     memset(head,-1,sizeof(head));
21 }
22 void add_edge(int v, int u, int cost)
23 {
24     g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
25 }
26 void dfs(int v, int fa, int cost)
27 {
28     dis[v] = cost;
29     for(int i = head[v]; i != -1; i = g[i].next)
30     {
31         int u = g[i].to;
32         if(u == fa) continue;
33         if(! dep[u])
34             dep[u] = dep[v] + 1, p[u][0] = v, dfs(u, v, dis[v] + g[i].cost);
35     }
36 }
37 void init1()
38 {
39     for(int j = 1; (1<<j) <= n; j++)
40         for(int i = 1; i <= n; i++)
41             p[i][j] = p[p[i][j-1]][j-1];
42 }
43 int LCA(int v, int u)
44 {
45     if(dep[v] < dep[u]) swap(v, u);
46     int d = dep[v] - dep[u];
47     for(int i = 0; (d>>i) != 0; i++)
48         if((d>>i) & 1) v = p[v][i];
49     if(v == u) return v;
50     for(int i = 20; i >= 0; i--)
51         if(p[v][i] != p[u][i]) v = p[v][i], u = p[u][i];
52     return p[v][0];
53 }
54 int main()
55 {
56     int t, q;
57     scanf("%d", &t);
58     while(t--)
59     {
60         init();
61         scanf("%d%d", &n, &m);
62         for(int i = 1; i < n; i++)
63         {
64             int a, b, c;
65             scanf("%d%d%d", &a, &b, &c);
66             add_edge(a, b, c), add_edge(b, a, c);
67         }
68         for(int i = 1; i <= m; i++)
69         {
70             int num, v;
71             scanf("%d", &num);
72             for(int j = 1; j <= num; j++)
73             {
74                 scanf("%d", &v);
75                 vec[i].push_back(v);
76             }
77         }
78         memset(dis, 0, sizeof dis);
79         memset(dep, 0, sizeof dep);
80         dfs(1, 0, 0);
81         init1();
82         scanf("%d", &q);
83         for(int i = 1; i <= q; i++)
84         {
85             int v, u, ans = INF;
86             scanf("%d%d", &v, &u);
87             for(size_t j = 0; j < vec[v].size(); j++)
88                 for(size_t k = 0; k < vec[u].size(); k++)
89                     ans = min(ans, dis[vec[v][j]] + dis[vec[u][k]] - dis[LCA(vec[v][j], vec[u][k])] * 2);
90             printf("%d\n", ans);
91         }
92         for(int i = 1; i <= m; i++) vec[i].clear();
93     }
94     return 0;
95 }

 

 hdu6118

费用流模板题,理解费用流就很容易a了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=508;
const int maxm=1008;
const int INF=0x3f3f3f3f;
struct fuck{
    int u,v,cap,cost,next;
}edge[maxm<<4];
int head[maxn];
int dis[maxn],pre[maxn],vis[maxn];
int tol;
int n;
void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int c)
{
    edge[tol].u=u;
    edge[tol].v=v;
    edge[tol].cap=c;
    edge[tol].cost=w;
    edge[tol].next=head[u];
    head[u]=tol++;
    edge[tol].u=v;
    edge[tol].v=u;
    edge[tol].cap=0;
    edge[tol].cost=-w;
    edge[tol].next=head[v];
    head[v]=tol++;
}
bool spfa()
{
    queue<int>    q;
    q.push(0);
    memset(dis,INF,sizeof(dis));
    memset(vis,false,sizeof(vis));
    dis[0]=0;vis[0]=true;pre[0]=-1;
    int i,u,v;
    while(!q.empty())
    {
        u=q.front();q.pop();
        vis[u]=false;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v;
            if(edge[i].cap>0&&dis[v]>dis[u]+edge[i].cost)
            {
                dis[v]=dis[u]+edge[i].cost;
                pre[v]=i;
                if(!vis[v])    
                {
                    vis[v]=true;
                    q.push(v);
                }
            }
        }
    }
    if(dis[n]>=INF)    return false;
    return true;
}
int min_costflow()
{
    int co,fl,u,i;
    co=fl=0;
    while(spfa())
    {
        int mi=INF;
        for (i = pre[n]; i != -1; i = pre[edge[i ^ 1].v]) {  
            if (mi > edge[i].cap)  
                mi = edge[i].cap;  
        }  
        for (i = pre[n]; i != -1; i = pre[edge[i ^ 1].v]) {  
            edge[i].cap -= mi;  
            edge[i ^ 1].cap += mi;   
        }  
        fl+=mi;
        if(dis[n]>0)    break;
        co +=mi*dis[n];
    }
    return co;
}
int main()
{
    int m,u,v,a,b,c,d,w;
    while(scanf("%d%d",&n,&m)==2)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            addedge(0,i,a,b);
            addedge(i,n+1,-c,d);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w,INF);
            addedge(v,u,w,INF);
        }
        n++;
        printf("%d\n",-min_costflow());
    }
    return 0;
}

 

hdu6119

先合并一样区间,然后二分就可以了

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=100008;
 4 struct fuck{
 5     int l,r;
 6 }f[maxn],g[maxn];
 7 int cmp(fuck a,fuck b)
 8 {
 9     if(a.l!=b.l)
10         return a.l<b.l;
11     return a.r<b.r;
12 }
13 int idx;
14 void init(int n)
15 {
16     int i=1,j=i+1;
17     idx=0;
18     while(i<=n)
19     {
20         g[++idx]=f[i];
21         while(j<=n)
22         {
23             if(f[j].l<=g[idx].r)
24             {
25                 g[idx].r=max(f[j].r,g[idx].r);
26                 j++;
27             }
28             else
29                 break;
30         }
31         i=j;
32     }
33 }
34 int dis[maxn];
35 int bs(int key,int n)
36 {
37     int left=1,right=n;
38     while(left<=right)
39     {
40         int mid=(left+right)>>1;
41         //printf("%d\n",mid);
42         if(dis[mid]>key)
43             right=mid-1;
44         else
45             left=mid+1;
46     }
47     return left-1;
48 }
49 int main()
50 {
51     int n,m;
52     while(scanf("%d%d",&n,&m)==2)
53     {
54         for(int i=1;i<=n;i++)
55             scanf("%d%d",&f[i].l,&f[i].r);
56         sort(f+1,f+n+1,cmp);
57         init(n);
58         dis[1]=0;
59         for(int i=2;i<=idx;i++)
60             dis[i]=g[i].l-g[i-1].r-1;
61         for(int i=2;i<=idx;i++)
62             dis[i]=dis[i-1]+dis[i];
63     //    for(int i=1;i<=idx;i++)    printf("%d ",dis[i]);printf("\n");
64         int ans=0;
65         for(int i=1;i<=idx;i++)
66         {
67             int x=bs(dis[i]+m,idx);
68             int len=g[x].r-g[i].l+1+m-dis[x]+dis[i];
69             if(len>ans)
70                 ans=len;
71         }
72         printf("%d\n",ans);
73     }
74     return 0;
75 }

 

  

 

posted on 2017-08-16 17:07  此剑之势愈斩愈烈  阅读(155)  评论(0编辑  收藏  举报

导航