官方题解: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; }