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