2017"百度之星"程序设计大赛 - 初赛(A) [ hdu 6108 小C的倍数问题 ] [ hdu 6109 数据分割 ] [ hdu 6110 路径交 ] [ hdu 6112 今夕何夕 ] [ hdu 6113 度度熊的01世界 ]
这套题体验极差。
PROBLEM 1001 - 小C的倍数问题
题
OvO http://acm.hdu.edu.cn/showproblem.php?pid=6108
(2017"百度之星"程序设计大赛 - 初赛(A) - 1001)
解
10进制下,各位数和是9的倍数的数能被9整除是因为 10^k-1=能被9整除
实质上就是10-1的因数有9
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; int calcu(int spl) { int i,j,ret=0; for(i=1;i*i<=spl;i++) if(spl%i==0) { ret++; if(i*i!=spl) ret++; } return ret; } int main() { int cas; int p; cin>>cas; while(cas--) { cin>>p; cout<<calcu(p-1)<<endl; } return 0; }
PROBLEM 1002 - 数据分割
题
OvO http://acm.hdu.edu.cn/showproblem.php?pid=6109
(2017"百度之星"程序设计大赛 - 初赛(A) - 1002)
解
每次拿到题目给的2个点,如果这两个点是相等的,则把这两个点所在的并查集合并,否则,找到这两个点的根,然后把把这两个根节点连一条边。
每次合并并查集的时候,要把相连的边也转移(选择边少的那个并查集转移)。
每次读入2个点,记录这两个点的具体值,存到栈里,以后每次清空,清空栈里这些值对应的位置即可,这样就算要清空L次也不会超时。
(思路来源于瞟了一眼某个我忘了在哪里的地方)
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <queue> using namespace std; const int N=2e5+44; struct node{ int u,v; int next; }edge[2*N]; struct clearpair { int a,b; } ; queue<clearpair> clearlist; int cnt,num; int head[N]; int answer[N],lanswer; int fa[N],tol[N],hav[N]; int t; void addedge(int u,int v) { edge[num].u=u; edge[num].v=v; edge[num].next=head[u]; head[u]=num++; } void changeedge(int id,int u) { edge[id].u=u; edge[id].next=head[u]; head[u]=id; } void init(int sz=100000) { t=0; num=0; for(int i=1;i<=sz;i++) { head[i]=-1; fa[i]=i; tol[i]=1; } while(!clearlist.empty()) clearlist.pop(); } void clear() { clearpair tmp; int a,b; t=0; num=0; while(!clearlist.empty()) { tmp=clearlist.front(); clearlist.pop(); head[tmp.a]=-1; fa[tmp.a]=tmp.a; tol[tmp.a]=1; head[tmp.b]=-1; fa[tmp.b]=tmp.b; tol[tmp.b]=1; } } int fff(int x) { if(fa[x]==x) return x; fa[x]=fff(fa[x]); return fa[x]; } bool merge(int a,int b) { int v,nxttmp,i,j,pa,pb,pv; pa=fff(a); pb=fff(b); if(pa==pb) return true; if(hav[pa]>hav[pb]) swap(pa,pb),swap(a,b); hav[pb]+=hav[pa]; fa[pa]=pb; for(i=head[pa],nxttmp=edge[i].next;i!=-1;i=nxttmp,nxttmp=edge[i].next) { v=edge[i].v; pv=fff(v); if(pv==pb) return false; changeedge(i,pb); } return true; } bool solve(int a,int b,int c) { int pa,pb; if(c==0) { pa=fff(a); pb=fff(b); if(pa==pb) return false; addedge(pa,pb); addedge(pb,pa); return true; } else return merge(a,b); } int main() { int i,j,a,b,c; int T; scanf("%d",&T); lanswer=0; init(); while(T--) { t++; scanf("%d%d%d",&a,&b,&c); clearlist.push((clearpair){a,b}); if(solve(a,b,c)==false) { answer[++lanswer]=t; clear(); } } printf("%d\n",lanswer); for(i=1;i<=lanswer;i++) printf("%d\n",answer[i]); return 0; }
PROBLEM 1003 - 路径交
题
Q∧Q http://acm.hdu.edu.cn/showproblem.php?pid=6110
(2017"百度之星"程序设计大赛 - 初赛(A) - 1003)
解
其实题目求的是[L,R]这个区间的路径的交,(而不是L,R两条的路径交),而且路径交的定义是[L,R]都覆盖的路径,(而不是只要有2条路径覆盖就行),
开个线段树,线段树中区间[li,ri]对应li~ri这些路径的交。
求路径交用LCA
(题意和思路来源于某大佬)
#include <iostream> #include <cstring> #include <cmath> #include <algorithm> #include <cstdio> using namespace std; typedef long long ll; const int MAXN=500044; int rmq[2*MAXN];//建立RMQ的数组 struct ST { int mm[2*MAXN];//mm[i]表示i的最高位,mm[1]=0,mm[2]=1,mm[3]=1,mm[4]=2 int dp[MAXN*2][35]; void init(int n) { mm[0]=-1; for(int i=1;i<=n;i++) { mm[i]=((i&(i-1))==0?mm[i-1]+1:mm[i-1]); dp[i][0]=i; } for(int j=1;j<=mm[n];j++) for(int i=1;i+(1<<j)-1<=n;i++) dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1]; } int query(int a,int b)//查询a到b间最小值的下标 { if(a>b)swap(a,b); int k=mm[b-a+1]; return rmq[dp[a][k]]<rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k]; } }; struct Node { int to,next,val; }; struct LCA2RMQ { int n;//结点个数 Node edge[2*MAXN];//树的边,因为是建无向边,所以是两倍 int tol;//边的计数 int head[MAXN];//头结点 bool vis[MAXN];//访问标记 int F[2*MAXN];//F是欧拉序列,就是DFS遍历的顺序 int P[MAXN];//某点在F中第一次出现的位置 int cnt; ST st; void init(int n)//n为所以点的总个数,可以从0开始,也可以从1开始 { this->n=n; tol=0; memset(head,-1,sizeof(head)); } void addedge(int a,int b,int val)//加边 { edge[tol].to=b; edge[tol].next=head[a]; edge[tol].val=val; head[a]=tol++; edge[tol].to=a; edge[tol].next=head[b]; edge[tol].val=val; head[b]=tol++; } int query(int a,int b)//传入两个节点,返回他们的LCA编号 { return F[st.query(P[a],P[b])]; } void dfs(int a,int lev) { vis[a]=true; ++cnt;//先加,保证F序列和rmq序列从1开始 F[cnt]=a;//欧拉序列,编号从1开始,共2*n-1个元素 rmq[cnt]=lev;//rmq数组是深度序列 P[a]=cnt; for(int i=head[a];i!=-1;i=edge[i].next) { int v=edge[i].to; if(vis[v])continue; dfs(v,lev+1); ++cnt; F[cnt]=a; rmq[cnt]=lev; } } void solve(int root) { memset(vis,false,sizeof(vis)); cnt=0; dfs(root,0); st.init(2*n-1); } }lca; struct Line { int a,b,flag; } line[MAXN],answer[MAXN],tree[MAXN*3]; ll dep[MAXN]; int lv[MAXN]; bool cmp(int x,int y) { return lv[x]>lv[y]; } Line merge(Line x,Line y) { Line ret; ret.flag=true; if(x.flag==false || y.flag==false) { ret.flag=false; return ret; } int lcax=lca.query(x.a,x.b),lcay=lca.query(y.a,y.b); if(lv[lcax]>lv[lcay]) swap(x,y),swap(lcax,lcay); int lca11=lca.query(x.a,y.a),lca12=lca.query(x.a,y.b),lca21=lca.query(x.b,y.a),lca22=lca.query(x.b,y.b); int que[5]; que[1]=lca11; que[2]=lca12; que[3]=lca21; que[4]=lca22; sort(que+1,que+4+1,cmp); ret.a=que[1]; ret.b=que[2]; // cout<<que[1]<<'-'<<que[2]<<endl; if(lv[ret.a]<lv[lcax] || lv[ret.b]<lv[lcax] || lv[ret.a]<lv[lcay] || lv[ret.b]<lv[lcay]) ret.flag=false; // cout<<ret.a<<' '<<ret.b<<' '<<lcax<<' '<<lcay<<' '<<ret.flag<<endl; return ret; } void build(int rt,int li,int ri) { if(li==ri) { tree[rt]=line[ri]; return ; } int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1; build(lc,li,mid); build(rc,mid+1,ri); tree[rt]=merge(tree[lc],tree[rc]); } Line query(int rt,int li,int ri,int lq,int rq) //get Line { bool flag=false; Line ret; if(lq<=li && ri<=rq) return tree[rt]; int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1; if(mid>=lq) { flag=true; ret=query(lc,li,mid,lq,rq); } if(mid+1<=rq) { if(flag==false) ret=query(rc,mid+1,ri,lq,rq); else ret=merge(ret,query(rc,mid+1,ri,lq,rq)); } return ret; } void getdepth(int rt,int pa,ll depnow,int lvnow) { int i,j,v; lv[rt]=lvnow; dep[rt]=depnow; for(i=lca.head[rt];i!=-1;i=lca.edge[i].next) { v=lca.edge[i].to; if(v==pa) continue; getdepth(v,rt,depnow+lca.edge[i].val,lvnow+1); } } ll getlength(int a,int b) { int c=lca.query(a,b); return dep[a]-dep[c]+dep[b]-dep[c]; } inline void read(int &ret) { int k=0; char f=1; char c=getchar(); for(;!isdigit(c);c=getchar() ) if(c=='-') f=-1; for(;isdigit(c);c=getchar() ) k=k*10+c-'0'; ret=k*f; } int main() { int i,j,a,b,c,n,m,q; ll ans; while(scanf("%d",&n)!=EOF) { lca.init(n); for(i=1;i<n;i++) { read(a); read(b); read(c); lca.addedge(a,b,c); } lca.solve(1); getdepth(1,-1,0,0); read(m); for(i=1;i<=m;i++) { read(line[i].a); read(line[i].b); line[i].flag=true; } build(1,1,m); read(q); for(i=1;i<=q;i++) { read(a); read(b); answer[i]=query(1,1,m,a,b); } for(i=1;i<=q;i++) { // cout<<answer[i].a<<' '<<answer[i].b<<endl; if(answer[i].flag) ans=getlength(answer[i].a,answer[i].b); else ans=0; printf("%lld\n",ans); } } return 0; } /* 4 1 2 2000000000 2 3 2000000000 1 4 2000000000 4 3 4 3 4 1 4 2 3 4 1 2 3 4 1 3 1 4 */
PROBLEM 1005 - 小今夕何夕
题
OvO http://acm.hdu.edu.cn/showproblem.php?pid=6112
(2017"百度之星"程序设计大赛 - 初赛(A) - 1005)
解
注意2-29
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; int a,b,c; int id; int inc[3]={1,2}; int jg(int spl) { if(spl%400==0) return 1; if(spl%100==0) return 0; if(spl%4==0) return 1; return 0; } int solve() { int ret=a+1,i,j,now=0; if(b==2 && c==29) { id=a+1; for(i=id;;i++,ret++) { now+=inc[jg(i)]; now%=7; if(jg(i) && now==0) return ret; } } id=a; if(b>2) id++; for(i=id;;i++,ret++) { now+=inc[jg(i)]; now%=7; // cout<<"ret: "<<ret<<' '<<"i: "<<i<<' '<<"now: "<<now<<endl; if(now==0) return ret; } } int main() { int i,j; int T; cin>>T; while(T--) { scanf("%d-%d-%d",&a,&b,&c); printf("%d\n",solve()); } return 0; }
PROBLEM 1006 - 度度熊的01世界
题
OvO http://acm.hdu.edu.cn/showproblem.php?pid=6113
(2017"百度之星"程序设计大赛 - 初赛(A) - 1006)
解
分步慢慢来
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> using namespace std; int n,m; char mp[111][111]; int tag1[111][111],tag0[111][111]; int dx[5]={0,0,1,-1}; int dy[5]={1,-1,0,0}; bool check(int x,int y) { if(x<=0 || x>n || y<=0 || y>m) return false; return true; } void dfs1(int x,int y) { int i,j,xx,yy; tag1[x][y]=1; for(i=0;i<4;i++) { xx=x+dx[i]; yy=y+dy[i]; if(check(xx,yy) && tag1[xx][yy]==0 && mp[xx][yy]=='1') dfs1(xx,yy); } } bool gettag1() { int i,j; for(i=1;i<=n;i++) for(j=1;j<=m;j++) if(mp[i][j]=='1') { dfs1(i,j); return true; } return false; } bool checkblock1() { int i,j; for(i=1;i<=n;i++) for(j=1;j<=m;j++) if(mp[i][j]=='1' && tag1[i][j]==0) return false; return true; } int dfs2(int x,int y) { int i,j,xx,yy,ret=1; tag0[x][y]=1; for(i=0;i<4;i++) { xx=x+dx[i]; yy=y+dy[i]; if(check(xx,yy)==false) { ret=0; continue; } if(tag0[xx][yy] || mp[xx][yy]=='1') continue; if(dfs2(xx,yy)==0) ret=0; } return ret; } int getblock0() { int ret=0,i,j; for(i=1;i<=n;i++) for(j=1;j<=m;j++) if(mp[i][j]=='0' && tag0[i][j]==0) ret+=dfs2(i,j); return ret; } int solve() { int i,j; if(gettag1()==false) return -1; if(checkblock1()==false) return -1; int cnt=getblock0(); if(cnt==0) return 1; if(cnt==1) return 0; return -1; } void init() { memset(tag1,0,sizeof(tag1)); memset(tag0,0,sizeof(tag0)); } int main() { int i,j; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) scanf("%s",mp[i]+1); init(); printf("%d\n",solve()); } return 0; }