2015 Multi-University Training Contest 3(HDOJ5316、5317、5319、5326)

来源:互联网 发布:硬笔软件app 编辑:程序博客网 时间:2024/06/02 01:06

官方题解:http://blog.sina.com.cn/duoxiao2015


这是放暑假后的第一场,上场在赶课设的deadline,就没去,然后队友爆零了(貌似他们晚上有考试,就只写了几小时的样子)

这场做第二题时脑抽,被卡烦了,就把写一半的代码扔给队友继续写


HDOJ5316

题意:n个数字,m个操作

操作0 a b,在[a,b]区间选出一个子序列,该子序列的所有相邻元素原位置奇偶不同,输出满足条件的子序列的各个数字之和最大值,子序列不能为空

操作1 a b,把位置a的数改成b

思路:明显线段树题,维护奇奇、奇偶、偶奇、偶偶的最大值就好

注意:负数的情况

#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;const int MAX = 100010;const LL INF = (LL)1<<60;int r, c, m;int op, x1, x2, y1, y2, x, v,T,Q,n,a,b;int data[MAX];struct tree{    LL s[2][2];//节点中需维护的东西};tree res;struct IntervalTree{    tree setv[MAX<<2];    void build(int num,int l,int r){//建树        int lc = num*2, rc = num*2+1;        //setv[num] = -1;        for(int i=0;i<2;i++){//初始化每个节点            for(int j=0;j<2;j++){                setv[num].s[i][j]=INF;            }        }        if(l == r){//初始化叶子节点值            //setv[num] = data[l];            if(l&1)setv[num].s[1][1]=data[l];            else setv[num].s[0][0]=data[l];            return ;        }        int mid = (l+r)>>1;        build(lc, l, mid);        build(rc, mid+1, r);        maintain(num,l,r);//如果需要向上合并就加    }    /*    void pushdown(int num)//向下分    {        int lc = num*2, rc = num*2+1;        if(setv[num] >= 0)        {            setv[lc] = setv[rc] = setv[num];            setv[num] = -1;        }    }*/    void maintain(int num,int l,int r){//向上合并        int lc = num*2, rc = num*2+1;        if(r>l){//合并更新非叶子节点值            for(int i=0;i<2;i++){                for(int j=0;j<2;j++){                    int f=1;//未更新                    if(setv[lc].s[i][j]!=INF){                        if(f){setv[num].s[i][j]=setv[lc].s[i][j];f=0;}                        else setv[num].s[i][j]=max(setv[num].s[i][j],setv[lc].s[i][j]);                    }                    if(setv[rc].s[i][j]!=INF){                        if(f){setv[num].s[i][j]=setv[rc].s[i][j];f=0;}                        else setv[num].s[i][j]=max(setv[num].s[i][j],setv[rc].s[i][j]);                    }                    if(setv[lc].s[i][0]!=INF&&setv[rc].s[1][j]!=INF){                        if(f){setv[num].s[i][j]=setv[lc].s[i][0]+setv[rc].s[1][j];f=0;}                        else setv[num].s[i][j]=max(setv[num].s[i][j],setv[lc].s[i][0]+setv[rc].s[1][j]);                    }                    if(setv[lc].s[i][1]!=INF&&setv[rc].s[0][j]!=INF){                        if(f){setv[num].s[i][j]=setv[lc].s[i][1]+setv[rc].s[0][j];f=0;}                        else setv[num].s[i][j]=max(setv[num].s[i][j],setv[lc].s[i][1]+setv[rc].s[0][j]);                    }                }            }        }        //else就是叶子节点        //更新节点值    }    void update(int num, int l, int r)    {        int lc = num*2, rc = num*2+1;        if(y1 <= l && r <= y2)        {            if(l&1)setv[num].s[1][1]=v;            else setv[num].s[0][0]=v;        }        else        {            //pushdown(num);//加了这句一般要再加两句maintain            int mid = l+(r-l)/2;            if(y1 <= mid) update(lc, l, mid);            if(y2 > mid) update(rc, mid+1, r);        }        maintain(num,l,r);//    }    void query(int num,int l,int r){//本题的查找结果        int lc = num*2, rc = num*2+1;        if(y1 <= l && r <= y2)        {            tree res2;            for(int i=0;i<2;i++){                for(int j=0;j<2;j++){                    res2.s[i][j]=res.s[i][j];                }            }            for(int i=0;i<2;i++){                for(int j=0;j<2;j++){                    int f=1;//未更新                    if(res2.s[i][j]!=INF){                        if(f){res.s[i][j]=res2.s[i][j];f=0;}                        else res.s[i][j]=max(res.s[i][j],res2.s[i][j]);                    }                    if(setv[num].s[i][j]!=INF){                        if(f){res.s[i][j]=setv[num].s[i][j];f=0;}                        else res.s[i][j]=max(res.s[i][j],setv[num].s[i][j]);                    }                    if(res2.s[i][0]!=INF&&setv[num].s[1][j]!=INF){                        if(f){res.s[i][j]=res2.s[i][0]+setv[num].s[1][j];f=0;}                        else res.s[i][j]=max(res.s[i][j],res2.s[i][0]+setv[num].s[1][j]);                    }                    if(res2.s[i][1]!=INF&&setv[num].s[0][j]!=INF){                        if(f){res.s[i][j]=res2.s[i][1]+setv[num].s[0][j];f=0;}                        else res.s[i][j]=max(res.s[i][j],res2.s[i][1]+setv[num].s[0][j]);                    }                }            }        }        else        {            //pushdown(num);            int mid = l+r>>1;            if(y1 <= mid) query(lc, l, mid);            if(y2 > mid) query(rc, mid+1, r);        }    }}pt;template <class T>inline bool read(T &ret) {   char c; int sgn;   if(c=getchar(),c==EOF) return 0; //EOF   while(c!='-'&&(c<'0'||c>'9')) c=getchar();   sgn=(c=='-')?-1:1;   ret=(c=='-')?0:(c-'0');   while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');   ret*=sgn;   return 1;}int main(){#ifdef DEBUG   freopen("CBin.txt","r",stdin);   //freopen("CBout.txt","w",stdout);#endif    cin>>T;    while(T--)    {        read(n);read(Q);        memset(pt.setv, -1, sizeof(pt.setv));        for(int i = 1; i <= n; ++i)        {            read(data[i]);        }        pt.build(1,1,n);        while(Q--)        {            read(op);read(a);read(b);            if(op){                y1=a;                y2=a;                v=b;                pt.update(1, 1, n);            }            else {                y1=a;                y2=b;                for(int i=0;i<2;i++){                    for(int j=0;j<2;j++){                        res.s[i][j]=INF;                    }                }                pt.query(1, 1, n);                LL r;                int f=1;                for(int i=0;i<2;i++){                    for(int j=0;j<2;j++){                        if(res.s[i][j]!=INF){                            if(f){r=res.s[i][j];f=0;}                            else r=max(r,res.s[i][j]);                        }                    }                }                cout<<r<<"\n";            }        }    }    return 0;}



HDOJ5317

题意:求区间[l,r]中maxGCD(F(i),F(j)),(L≤i<j≤R),其中F(i)表示i的质因子有多少种

思路:由于测试数据有百万组,所以要用O(1)的方法,容易发现结果最大是7

第一步:先用修改过的素数筛法在伪线性的时间预处理所有的F(i)

第二步:接着再预处理每个数为起点对应的每个maxgcd值的最小范围(这步不是我写的,思路是赛后想到的,队友可能不是按这思路AC的)

接下来就可以O(1)的查找了

代码第二步是队友写的,就不贴了


HDOJ5319

题意:给n行的图,RGB代表3种颜色,点代表空白,现在让你画出这个图,求最少几笔,R只能斜着‘\’这样画,B只能斜着‘/’这样画,RB都画过的格子是G,一个格子不能被相同画笔画两次

思路:G必定被RB划过,可以先把G画好,再画剩下的

注意:给的是n行的图,不是n*n的图

#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <cmath>using namespace std;typedef long long LL;const int MAXN=50+10;int T,n,m;int g[MAXN][MAXN],now[MAXN][MAXN];int sum;string c;void init(){    m=0;    for (int i=0;i<n;++i){        cin>>c;        m=c.size();        for (int j=0;j<m;++j){            if(c[j]=='.')g[i][j]=0;            if(c[j]=='R')g[i][j]=1;            if(c[j]=='B')g[i][j]=2;            if(c[j]=='G')g[i][j]=3;        }    }    sum=0;    memset(now,0,sizeof(now));}void drawR(int x,int y){    sum++;    //int k=x-y;    for (int i=0;x-i>=0&&y-i>=0&&x-i<n&&y-i<m;++i){        if((g[x-i][y-i]==3&&(now[x-i][y-i]==0||now[x-i][y-i]==2))||(g[x-i][y-i]==1&&(now[x-i][y-i]==0)))now[x-i][y-i]+=1;        else break;    }    for (int i=-1;x-i>=0&&y-i>=0&&x-i<n&&y-i<m;--i){        if((g[x-i][y-i]==3&&(now[x-i][y-i]==0||now[x-i][y-i]==2))||(g[x-i][y-i]==1&&(now[x-i][y-i]==0)))now[x-i][y-i]+=1;        else break;    }}void drawB(int x,int y){    sum++;    for (int i=0;x-i>=0&&y+i>=0&&x-i<n&&y+i<m;++i){        if((g[x-i][y+i]==3&&(now[x-i][y+i]==0||now[x-i][y+i]==1))||(g[x-i][y+i]==2&&(now[x-i][y+i]==0)))now[x-i][y+i]+=2;        else break;    }    for (int i=-1;x-i>=0&&y+i>=0&&x-i<n&&y+i<m;--i){        if((g[x-i][y+i]==3&&(now[x-i][y+i]==0||now[x-i][y+i]==1))||(g[x-i][y+i]==2&&(now[x-i][y+i]==0)))now[x-i][y+i]+=2;        else break;    }}void work(){    for (int i=0;i<n;++i){        for (int j=0;j<m;++j){            if(g[i][j]==3&&now[i][j]==0){drawR(i,j);drawB(i,j);}            if(g[i][j]==3&&now[i][j]==1){drawB(i,j);}            if(g[i][j]==3&&now[i][j]==2){drawR(i,j);}        }    }    for (int i=0;i<n;++i){        for (int j=0;j<m;++j){            if(g[i][j]==1&&now[i][j]==0){drawR(i,j);}            if(g[i][j]==2&&now[i][j]==0){drawB(i,j);}        }    }}int main(){#ifdef DEBUG   freopen("CBin.txt","r",stdin);   //freopen("CBout.txt","w",stdout);#endif    cin>>T;    while(T--){        cin>>n;        init();        work();        cout<<sum<<"\n";    }    return 0;}


HDOJ5326

题意:给一颗大小为n的树,问该树中节点的后代数量恰好为k的有几个

思路:水题,我直接套了我以前写的树形DP的模版

#include <stdio.h>#include <string.h>#include <math.h>#include <algorithm>#include <vector>#include <iostream>using namespace std;//typedef long long LL;const int MAXN = 110;int n,e,s,m,k;int dp[MAXN];bool f[MAXN];int sum;struct Edge{    int next;    Edge();    Edge(int b){next=b;}};vector<Edge>dv[MAXN];void init(){    for(int i=0;i<=n;i++) dv[i].clear();    memset(f,0,sizeof(f));    memset(dp,0,sizeof(dp));    sum=0;}void dfs(int p,int fa){    int son;    dp[p]+=1;    for(int i=0;i<dv[p].size();i++)    {        son=dv[p][i].next;        if(son^fa){            dfs(son,p);            dp[p]+= dp[son];            //cout<<son<<p<<" "<<dv[p][i].val<<" "<<dp[son]<<" "<<res<<"\n";        }    }        if(dp[p]==k+1)sum++;}int main(){#ifdef DEBUG   freopen("CBin.txt","r",stdin);   //freopen("CBout.txt","w",stdout);#endif    while(~scanf("%d%d",&n,&k))    {        init();        for(int i=1;i<n;i++)        {            int b,c;            scanf("%d%d",&b,&c);            dv[c].push_back(Edge(b));            dv[b].push_back(Edge(c));            f[c]=1;        }        int root;        for(int i=1;i<=n;i++)        {            if(!f[i]){root=i;break;}        }        dfs(root,0);        cout<<sum<<"\n";        //printf("%d\n",max(dp[root][0],dp[root][1]));    }    return 0;}



0 0