zsacm20120226省赛前个人赛第1场(结题报告)
之前做过的线段树,单点更新,难度不大,连标记下传也不用了,用了之前学习到的代码,就是代码记忆不够熟练,中间有的地方总是写错,简直浪费时间。
#include <stdio.h> #include <algorithm> using namespace std; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define maxn 200001 int MAX[maxn<<2]; int max(int a,int b) { return a>b?a:b; } void pushup(int rt) { MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); } void build(int l,int r,int rt) { if(l==r) { scanf("%d",&MAX[rt]); return ; } int mid=(l+r)>>1; build(lson); build(rson); pushup(rt); } void update(int p,int sc,int l,int r,int rt) { if(l==r) { MAX[rt]=sc; return ; } int mid=(l+r)>>1; if(p<=mid) update(p,sc,lson); else update(p,sc,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { return MAX[rt]; } int mid=(l+r)>>1; int ret=0; if(L<=mid) ret=max(ret,query(L,R,lson)); if(R>mid) ret=max(ret,query(L,R,rson)); return ret; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { build(1,n,1); while(m--) { char st[2]; int a,b; scanf("%s%d%d",st,&a,&b); if(st[0]=='Q') printf("%d\n",query(a,b,1,n,1)); else update(a,b,1,n,1); } } return 0; }
2.http://acm.hdu.edu.cn/showproblem.php?pid=3333
一看名字就知道又是一个树的题目,解释:图灵树。
题意很简单,求给定数组中一段区间不同数字的和。刚开始想到大数据要离散化,线段树求值,可是总是怎么多写不出来。看了网上的报告瞬间觉得无语,这么简单。思路没错,果然还是代码能力的问题。
思路:假定原始数组是 a = 1,1,4.去重之后是 b = 1,4.
那么建立一个 c 数组,保存 a 中的元素在 b 中的下标。c = 0,0,2.
对 c 建立线段树查询即可。
#include<iostream> #include<cmath> #include<algorithm> #define MAXN 100001 using namespace std; int n; int a[MAXN]; __int64 c[MAXN]; int pre[MAXN]; int next[MAXN]; __int64 res[MAXN]; struct node { int s,e; int pos; }q[100010]; int lowbit(int x) { return x & (x ^ (x-1)); } __int64 sum(int x) { __int64 sum = 0; while(x > 0) { sum += c[x]; x -= lowbit(x); } return sum; } void modify(int i,int x,int n) { while(i <= n) { c[i] += x; i += lowbit(i); } } bool cmp(node a,node b) { if (a.s == b.s) return a.e < b.e; return a.s < b.s; } int main() { int t,m; while(scanf("%d",&t)!=EOF) { while(t--) { memset(a,0,sizeof(a)); memset(c,0,sizeof(c)); scanf("%d",&n); for(int i = 1;i <= n;++i) scanf("%d",&a[i]); for(int i = n;i >= 1;--i) { pre[i] = -1; for(int j = i-1;j >= 1;--j) if (a[i] == a[j]) { pre[i] = j; break; } }//计算next for(int i = 1;i <= n;++i) { next[i] = n+1; for(int j = i + 1;j <= n;++j) if (a[i] == a[j]) { next[i] = j; break; } } for(int i = 1;i <= n;++i) { if (pre[i] == -1) modify(i,a[i],n); else modify(i,0,n); } scanf("%d",&m); for(int i = 0;i < m;++i) { scanf("%d%d",&q[i].s,&q[i].e); q[i].pos = i; } sort(q,q+m,cmp); int index = 1; for(int i = 0;i < m;++i) { for(int j = index;j < q[i].s;++j) { modify(j,-a[j],n); pre[next[j]] = -1; modify(next[j],a[next[j]],n); } index = q[i].s; __int64 ans; if (q[i].s == 1) { ans = sum(q[i].e); // printf("ans:%I64d\n",ans); } else { //cout<<sum(q[i].e)<<' '<<sum(q[i].s - 1)<<endl; ans = sum(q[i].e) - sum(q[i].s - 1); } res[q[i].pos] = ans; } for(int i = 0;i < m;++i) printf("%I64d\n",res[i]); } } return 0; }
3.http://acm.hdu.edu.cn/showproblem.php?pid=3342
这道题主要就是判断是否能拓扑排序(就是不能构成环),能的话就输出YES,不能侧输出NO。题意耐心看就出来了。
#include<iostream> using namespace std; #define maxn 105 int map[maxn][maxn]; int degree[maxn]; int n,m; int top; int f[maxn]; void toposort() { int i,j,k; for(i=0;i<n;i++) { for(j=0;j<n;j++) { if(degree[j]==0) { degree[j]--; top++; for(k=0;k<n;k++) { if(map[j][k]) degree[k]--; } break; } } } } int main() { int i,j,k; while(cin>>n>>m) { if(n==0&&m==0) break; memset(map,0,sizeof(map)); memset(degree,0,sizeof(degree)); int a,b; while(m--) { cin>>a>>b; if(map[a][b]==0) { map[a][b]=1; degree[b]++; } } top=0; toposort(); if(top==n) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
4.http://acm.hdu.edu.cn/showproblem.php?pid=1284
怎么说,就是数学题,逻辑考一考,难度不是很大,转来转去的。只需要计算出可以换多少3分的和多少2分的就可以了。
#include <stdio.h> int main () { int n,s,i; while (scanf("%d",&n)!=EOF) { s=n/3+1;//计算3分的 for (i=0;i<=n/3;i++) s+=(n-3*i)/2;//计算2分的 不过因为已经算过3分的 所以那一部分要先减掉 printf ("%d\n",s); } return 0; }
5.http://acm.hdu.edu.cn/showproblem.php?pid=2053
简单题,看题目就好。水过的。
#include <iostream> using namespace std; int main() { int i,c,n; while(scanf("%d",&n)!=EOF) { for(i=1,c=0;i<=n;i++) { if(n%i==0) c++; } printf("%d\n",c&1); } return 0; }
6.http://acm.hdu.edu.cn/showproblem.php?pid=2617
此题用一般的遇到一个h就向下查找会超时,即使是把那些不是h,a,p,y的字符去掉重新组成一个字符串,再用此方法也会超时。不过做到最好发现还是一个个查找就对了,就是自己写聪明点。
#include<cstdio> #include<iostream> using namespace std; #include<cstring> int main() { char s[10001]; int h,a,p1,p2,y,i; while(gets(s)!=NULL) { h=a=p1=p2=y=0; for(i=0;s[i]!='\0';i++) { if(s[i]=='h') h++; if(s[i]=='a') { if(h) {h--;a++;} } else if(s[i]=='p') { if(p1) {p1--;p2++;} else if(a) {p1++;a--;} } else if(s[i]=='y') { if(p2) {y++;p2--;} } } cout<<y<<endl; } return 0; }
7.http://acm.hdu.edu.cn/showproblem.php?pid=4151
水题,打表,二分暴力查找。
#include<stdio.h> #include<string.h> int a[1000000]; int main() { int b[10]; int i,j,n,k=1,low,high,mid; for(i=1;i<=10000000;i++) { memset(b,0,sizeof(b)); j=i; while(j) { if(b[j%10]!=1) { b[j%10]=1; j/=10;} else break; } if(j==0) a[k++]=i; } while(scanf("%d",&n)!=EOF) { low=1; high=k-1; while(low<=high) { mid=(low+high)/2; if(a[mid]>=n) high=mid-1; else low=mid+1; } printf("%d\n",high); } return 0; }
8.http://acm.hdu.edu.cn/showproblem.php?pid=3764
水题,注意题目说的返回的时候没有充电站,所以距离差要小于100.
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std; int lu[1423000]; int main() { int n,m,i,j; int flag; while(~scanf("%d",&n),n) { flag=1; for(i=0;i<n;i++) scanf("%d",&lu[i]); sort(lu,lu+n); for(i=1;i<n;i++) if(lu[i]-lu[i-1]>200) { flag=0; break; } if(flag&&1422-lu[n-1]>100) flag=0; if(flag) puts("POSSIBLE"); else puts("IMPOSSIBLE"); } return 0; }
9.http://acm.hdu.edu.cn/showproblem.php?pid=4156
水题,判断是不是勾股三角形。
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std; int main() { int a,b,c; int num[3]; while(~scanf("%d%d%d",&num[0],&num[1],&num[2])&&(num[0]&&num[1]&&num[2])) { sort(num,num+3); if(num[0]*num[0]+num[1]*num[1]==num[2]*num[2]) puts("right"); else puts("wrong"); } return 0; }
总结:
老师完美的出题,大大的感受了AC的快感。以后就没这么简单了.