2015长春网络赛题解

A.http://acm.hdu.edu.cn/showproblem.php?pid=5437

思路:维护一个优先队列,模拟开门,枚举每一个人,同时记录当先开门的位置,如果人数等于开门位置,就从队列中取出min(size(),q),放到我们的答案队列中。注意开门时间可能相同,所以要先排序,再加一个循环。还有最后一次开门,剩下的人都放进来。注意他说的只有两次ni会超过10000,所以我们可以在输入时记下查询的最大位置。当答案队列中的人大于查询的最大位置就可以退出循环了,这样就不会超时了。因为代码找不到了,就不贴了。

B.http://acm.hdu.edu.cn/showproblem.php?pid=5438

思路:在输边的时候记录每个点的度数。然后一遍循环,bfs模拟删点。最后再tarjan求联通分量。这个地方可以考虑直接bfs求联通分量的点数应该更简单。

#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int MAXN=11000;
const int MAXM=110000;
struct Edge{
    int v,nex;
}edge[MAXM];

vector<int> G[MAXN];
ll value[MAXN];
int dfn[MAXN];
int low[MAXN];
int deg[MAXN];
int head[MAXN];
int stack[MAXN];
bool instack[MAXN];
int inde,top,block;
vector<int> bblock[MAXN];
int T,p,m,u,v,tot;

void addedge(int u,int v)
{
    edge[tot].v=v;
    edge[tot].nex=head[u];
    head[u]=tot++;
}

void bfs(int u)
{
    int tmp;
    queue<int> que;
    que.push(u);
    while(!que.empty())
    {
        tmp=que.front();
        que.pop();
        for(int i=0;i<G[tmp].size();i++)
        {
            v=G[tmp][i];
            G[tmp][i]=0;
            deg[u]--,deg[v]--;
            if(deg[v]==1)
                que.push(v);
        }
    }
}

void tarjan(int u)
{
    int v;
    low[u]=dfn[u]=++inde;
    stack[top++]=u;
    instack[u]=true;
    for(int i=head[u];i!=-1;i=edge[i].nex)
    {
        v=edge[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            if(low[u]>low[v])
                low[u]=low[v];
        }
        else if(instack[v]&&low[u]>dfn[v])
            low[u]=dfn[v];
    }
    if(low[u]==dfn[u])
    {
        block++;
        do{
            v=stack[--top];
            instack[v]=false;
            bblock[block].push_back(v);
        }
        while(v!=u);
    }
}

void init()
{
    for(int i=0;i<MAXN;i++)
    {
        bblock[i].clear();
        G[i].clear();
    }
    memset(value,0,sizeof(value));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(deg,0,sizeof(deg));
    memset(head,-1,sizeof(head));
    memset(instack,0,sizeof(instack));
    block=top=inde=tot=0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&p,&m);
        for(int i=1;i<=p;i++)
            scanf("%I64d",&value[i]);
        while(m--)
        {
            scanf("%d%d",&u,&v);
            if(v==u)
                continue;
            G[u].push_back(v);
            G[v].push_back(u);
            deg[u]++,deg[v]++;
        }
        for(int i=1;i<=p;i++)
            if(deg[i]==1)
                bfs(i);
        for(int i=1;i<=p;i++)
            for(int j=0;j<G[i].size();j++)
                if(G[i][j])
                    addedge(i,G[i][j]);
        for(int i=1;i<=p;i++)
            if(!dfn[i])
                tarjan(i);
        ll ans=0;
        for(int i=0;i<=block;i++)
            if(bblock[i].size()>1&&bblock[i].size()%2)
                for(int j=0;j<bblock[i].size();j++)
                    ans+=value[bblock[i][j]];
        printf("%I64d\n",ans);
    }
    return 0;
}

E.http://acm.hdu.edu.cn/showproblem.php?pid=5441

思路:离线并查集。把边和询问分别排序。然后往里面加边,设边e的点u,v所在集合的节点数量为cnt[u],cnt[v].那么ans=ans-cnt[u]*(cnt[u]-1)-cnt[v]*(cnt[v]-1)+(cnt[u]+cnt[v])*(cnt[u]+cnt[v]-1), 再把u集合并入v集合,cnt[u]+=cnt[v]。

#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=25000;
const int MAXM=110000;
const int MAXQ=6000;
int par[MAXN];
int cnt[MAXN];
int ansx[MAXQ];
int n,m,q,T;
struct Edge{
    int u,v,w;
}edge[MAXM];

struct Query{
    int w,id;
}query[MAXQ];

bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}

bool cmp2(Query a,Query b)
{
    return a.w<b.w;
}
int find(int x)
{
    return x==par[x]?x:par[x]=find(par[x]);
}

void init()
{
    for(int i=0;i<MAXN;i++)
        cnt[i]=1,par[i]=i;
}

int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d%d",&n,&m,&q);
        for(int i=0;i<m;i++){
            //if(u==v) continue;
            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        }
        sort(edge,edge+m,cmp);
        for(int i=0;i<q;i++)
        {
            scanf("%d",&query[i].w);
            query[i].id=i;
        }
        sort(query,query+q,cmp2);
        int sh=0;
        int ans=0;
        for(int i=0;i<m;i++)
        {
            Edge e=edge[i];
            //printf("%d %d %d\n",e.w,sh+,query[sh]);
            while(sh<q&&e.w>query[sh].w)
                ansx[query[sh++].id]=ans;
            int u=find(e.u);
            int v=find(e.v);
            if(u==v)
                continue;
            ans-=cnt[u]*(cnt[u]-1);
            ans-=cnt[v]*(cnt[v]-1);
            par[v]=u;
            cnt[u]+=cnt[v];
            ans+=cnt[u]*(cnt[u]-1);
        }
        while(sh<q)
            ansx[query[sh++].id]=ans;
        for(int i=0;i<q;i++)
            printf("%d\n",ansx[i]);
    }
    return 0;
}

G.http://acm.hdu.edu.cn/showproblem.php?pid=5443

签到题,暴力也能过。

H.http://acm.hdu.edu.cn/showproblem.php?pid=5444

思路:模拟建树就好。

#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=1100;
struct Node{
    int l,r;
    int id;
}node[MAXN];

void find(int pos,int to)
{
    int x=0;
    while(1)
    {
        if(node[x].id>=to)
        {
            if(!node[x].r)
            {
                node[x].r=pos;
                break;
            }
            else
                x=node[x].r;
        }
        else
        {
            if(!node[x].l)
            {
                node[x].l=pos;
                break;
            }
            else
                x=node[x].l;
        }
    }
}

void solve(int to)
{
    int x=0;
    while(1)
    {
        if(node[x].id==to)
            break;
        if(node[x].id>to)
        {
            printf("E");
            x=node[x].r;
        }
        else
        {
            printf("W");
            x=node[x].l;
        }
    }
}

int T,n,q,to;

int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        memset(node,0,sizeof(node));
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&node[i].id);
            if(i==0)
                continue;
            find(i,node[i].id);
        }
        scanf("%d",&q);
        for(int i=0;i<q;i++)
        {
            scanf("%d",&to);
            solve(to);
            puts("");
        }
    }
    return 0;
}

时间: 2024-10-14 05:14:01

2015长春网络赛题解的相关文章

2015长春网络赛总结

早上七点多就(冻)醒来了,训练了一个暑假,acm生涯的第一场网络赛,很激动. 九点开打,我拔不出网线,用的机房电脑,装的cb有问题,不能编译,只好用dev.男神电脑插上网线没有网,习惯了linux可能不习惯吧.这提醒我们以后一定要早点去把环境调好. 第三分钟,G题有人A了.我跟560开始看题,男神还在弄电脑.题意是给你n个数(n<1000),然后q(q<1000)次询问,要求你输出[l,r]区间的最大值.数据很小,我说暴力,然后560说线段树,然后模板13分钟1Y.然后560开始搞J,一个貌似

2015长春网络赛1001 求连通快数量的问题dfs

Ponds Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1288    Accepted Submission(s): 429 Problem Description Betty owns a lot of ponds, some of them are connected with other ponds by pipes, a

hdu 5441 (2015长春网络赛E题 带权并查集 )

n个结点,m条边,权值是 从u到v所花的时间 ,每次询问会给一个时间,权值比 询问值小的边就可以走 从u到v 和从v到u算不同的两次 输出有多少种不同的走法(大概是这个意思吧)先把边的权值 从小到大排序 询问值也按从小到大排序num记录集合里元素的个数每合并两个集合 ans增加 2*num[u]*num[v] Sample Input15 5 3 //n w q2 3 63341 5 157243 5 57054 3 123821 3 2172660001000013000 Sample Out

hdu 5446(2015长春网络赛J题 Lucas定理+中国剩余定理)

题意:M=p1*p2*...pk:求C(n,m)%M,pi小于10^5,n,m,M都是小于10^18. pi为质数 M不一定是质数 所以只能用Lucas定理求k次 C(n,m)%Pi最后会得到一个同余方程组x≡B[0](mod p[0])x≡B[1](mod p[1])x≡B[2](mod p[2])......解这个同余方程组 用中国剩余定理 Sample Input19 5 23 5 Sample Output6 1 # include <iostream> 2 # include <

Hdu 5439 Aggregated Counting (2015长春网络赛 ACM/ICPC Asia Regional Changchun Online 找规律)

题目链接: Hdu 5439 Aggregated Counting 题目描述: 刚开始给一个1,序列a是由a[i]个i组成,最后1就变成了1,2,2,3,3,4,4,4,5,5,5.......,最后问a[i]==n(i最大)时候,i最后一次出现的下标是多少? 解题思路: 问题可以转化为求a[i] == n (i最大),数列前i项的和为多少. index: 1 2 3 4 5 6 7 8 9 10 a:        1 2 2 3 3 4 4 4 5 5 可以观察出:ans[1] = 1,

2015长春网络赛 1006(后缀数组或者最小表示法)

给一个字符串,这个字符串是首位连起来的,要我们输出从哪个位置开始,顺时针走,还是你时针走,字典序最大 如果字典序最大的字符串有多个,开始的下标越小越好,如果开始的下标又相同,那么顺时针的优先. 原字符串为abab,那么只要在后面加上原字符串,变成abababab#,#是一个很小的字符, 然后进行后缀数组,sa[n-1]就是顺指针字典序最大的下标,n为abababab#的长度 逆时针,只要将字符串倒过来,[email protected],@是一个很大的字符, 然后进行后缀数组, 那么只要遍历ra

Hdu 5445 Food Problem (2015长春网络赛 ACM/ICPC Asia Regional Changchun Online)

题目链接: Hdu  5445 Food Problem 题目描述: 有n种甜点,每种都有三个属性(能量,空间,数目),有m辆卡车,每种都有是三个属性(空间,花费,数目).问至少运输p能量的甜点,花费最小是多少? 解题思路: 明显可以看出是多重背包搞两次,但是数据范围太大了,背包要到2*1e6,感觉会TLe.还是呆呆的写了一发,果断超啊!然后滚回去看背包九讲课件了,看到了二进制压缩的时候,感觉可以搞这个题目.试了一下果然AC,原本物品数目是100*100,二进制压缩以后也就是100*log210

2015北京网络赛A题The Cats&#39; Feeding Spots

题意:给你一百个点,找个以这些点为中心的最小的圆,使得这个圆恰好包含了n个点,而且这个圆的边界上并没有点 解题思路:暴力枚举每个点,求出每个点到其他点的距离,取第n大的点,判断一下. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<iostream> 5 #include<memory.h> 6 using namespace std; 7 const i

2015北京网络赛 Couple Trees 倍增算法

2015北京网络赛 Couple Trees 题意:两棵树,求不同树上两个节点的最近公共祖先 思路:比赛时看过的队伍不是很多,没有仔细想.今天补题才发现有个 倍增算法,自己竟然不知道.  解法来自 qscqesze ,这个其实之前如果了解过倍增的话还是不是很难,不过这题的数据也不是很给力,极限数据理论上是过不了的.  其他解法有树链剖分?并不是很清楚.就这样水过了吧... 1 #include <iostream> 2 #include <cstdio> 3 #include &l