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的快感。以后就没这么简单了.
浙公网安备 33010602011771号