920考试题解
Cleaning Up 打扫卫生
时间限制: 1 Sec 内存限制: 128 MB
Description
有N头奶牛,每头那牛都有一个标号Pi,1 <= Pi <= M <= N <= 40000。现在Farmer John要把这些奶牛分成若干段,定义每段的不河蟹度为:若这段里有k个不同的数,那不河蟹度为k*k。那总的不河蟹度就是所有段的不河蟹度的总和。
Input
第一行:两个整数N,M
第2..N+1行:N个整数代表每个奶牛的编号
Output
一个整数,代表最小不河蟹度
Sample Input
1
2
1
3
2
2
3
4
3
4
3
1
4
Sample Output
f(i)=min{f(pos(j))+j∗j}(0<=j<=n√)。为了维护pos,用cnt数组记录[pos[j],i]一共有多少种颜色,当i从i+1转移到时候可以通过判断i的pre来更新cnt,如果cnt(j)>j即不合法,pos需要向后移动直到通过nxt某种颜色被完全删除出区间。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int sj=40010; int n,m,cnt[sj],f[sj],pos[sj],nxt[sj],pre[sj],a1; void bj(int &x,int y) { x=x<y?x:y; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a1); nxt[cnt[a1]]=i,pre[i]=cnt[a1]; cnt[a1]=i,nxt[i]=n+1; f[i]=i; } memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;i++) for(int j=1;j<=sqrt(n);j++) { if(pre[i]<=pos[j]) cnt[j]++; while(cnt[j]>j) { pos[j]++; if(nxt[pos[j]]>i) cnt[j]--; } bj(f[i],f[pos[j]]+j*j); } printf("%d",f[n]); return 0; }
覆盖问题
时间限制: 1 Sec 内存限制: 256 MB
Description
Input
Output
一行,输出最小的L值。
Sample Input
0 1
0 -1
1 0
-1 0
Sample Output
HINT
100%的数据,N<=20000
题解
一个思路诡异的搜索题……并没有看出来它是个搜索,虽然我诚心诚意地打了二分又用一种奇奇怪怪的方式强行check,知道在边界上会出些问题,但是没办法解决就由他去了,没想到真的只有10分。
为什么是三个正方形?因为矩形有四条边!在任何情况下正方形再不济,也要贴着最小覆盖矩形的一个角。所以枚举它在四个角上的情况,标记哪些点被覆盖再进行下一层dfs,在下一层仍是最小覆盖矩形的方法,到三层后检查是否所有点都被覆盖。代码的实现本身毫无难度,关键在于发现一些必要的规律找到解题的方法。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int sj=20005; int n,ge; long long zj,yj,ax,ix,ay,iy,mid; bool op; struct point { long long x,y; }p[sj]; bool fg[sj],qk; bool dfs(int st) { qk=1; for(int i=1;i<=n;i++) if(!fg[i]) { qk=0; break; } if(qk) return 1; if(st>3) return 0; long long zb,xb,sb,yb; zb=xb=0x7fffffff,sb=yb=-0x7fffffff; bool zt[sj]; memcpy(zt,fg,sizeof(fg)); for(int i=1;i<=n;i++) if(!fg[i]) { if(p[i].x<zb) zb=p[i].x; if(p[i].x>yb) yb=p[i].x; if(p[i].y>sb) sb=p[i].y; if(p[i].y<xb) xb=p[i].y; } for(int i=1;i<=n;i++) if(!fg[i]&&p[i].y>=sb-mid&&p[i].x<=zb+mid) fg[i]=1; if(dfs(st+1)) return 1; memcpy(fg,zt,sizeof(zt)); for(int i=1;i<=n;i++) if(!fg[i]&&p[i].y<=xb+mid&&p[i].x<=zb+mid) fg[i]=1; if(dfs(st+1)) return 1; memcpy(fg,zt,sizeof(zt)); for(int i=1;i<=n;i++) if(!fg[i]&&p[i].y>=sb-mid&&p[i].x>=yb-mid) fg[i]=1; if(dfs(st+1)) return 1; memcpy(fg,zt,sizeof(zt)); for(int i=1;i<=n;i++) if(!fg[i]&&p[i].x<=xb+mid&&p[i].x>=yb-mid) fg[i]=1; if(dfs(st+1)) return 1; return 0; } int main() { scanf("%d",&n); ix=iy=0x7fffffff; ax=ay=-0x7fffffff; for(int i=1;i<=n;i++) { scanf("%lld%lld",&p[i].x,&p[i].y); if(p[i].x<ix) ix=p[i].x; if(p[i].y<iy) iy=p[i].y; if(p[i].x>ax) ax=p[i].x; if(p[i].y>ay) ay=p[i].y; } zj=0,yj=ax-ix; if(ay-iy>yj) yj=ay-iy; while(zj<yj) { memset(fg,0,sizeof(fg)); mid=(zj+yj)>>1; if(dfs(1)) yj=mid; else zj=mid+1; } printf("%lld",zj); return 0; }
高速公路
时间限制: 2 Sec 内存限制: 256 MB
Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站。
Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。
政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。
无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l<r),在第l个到第r个收费站里等概率随机取出两个不同的收费站a和b,那么从a行驶到b将期望花费多少费用呢?
Input
第一行2个正整数N,M,表示有N个收费站,M次调整或询问
接下来M行,每行将出现以下两种形式中的一种
C l r v 表示将第l个收费站到第r个收费站之间的所有道路的通行费全部增加v
Q l r 表示对于给定的l,r,要求回答小A的问题
所有C与Q操作中保证1<=l<r<=N
Output
对于每次询问操作回答一行,输出一个既约分数
若答案为整数a,输出a/1
Sample Input
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4
Sample Output
8/3
17/6
HINT
数据规模
所有C操作中的v的绝对值不超过10000
在任何时刻任意道路的费用均为不超过10000的非负整数
所有测试点的详细情况如下表所示
Test N M
1 =10 =10
2 =100 =100
3 =1000 =1000
4 =10000 =10000
5 =50000 =50000
6 =60000 =60000
7 =70000 =70000
8 =80000 =80000
9 =90000 =90000
10 =100000 =100000
题解
很明显的每个收费站对答案的贡献为v[i]*(i-l+1)*(r-i+1),然而我考试的时候一直想着怎样维护整个的答案,想都没想就开始线段树。线段树越打越烦躁,感觉根本就没有办法维护出来,干脆弃了线段树去写裸暴力。但是尽管它是个n^无数的裸暴力我也没想到居然能全T掉,这就很尴尬了,按照题目中给的范围不至于啊……
把第一行那个式子拆开,得到
Σ(i=l,r) -i^2 *a[i]+i*a[i]*(l+r)-(r+1)*(l-1)*a[i]=-Σ(i=l,r)-i^2 *a[i]+(l+r)Σ(i=1,r)i*a[i]-(r+1)*(l-1)Σ(i=l,r)a[i],这样不就可以分别维护i*i*a[i],i*a[i],a[i]的区间和了。如果过去线段树的很多题中心都在于怎样维护,这道题也提供了一个关于“维护什么”的新思路。只要有时间就把式子拆一拆,有益解题有益身心健康啊……
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int sj=100010; int n,m; long long ans,a1,a2,tp,gcd,a3; char a; struct Tree { long long fa,ya,aa,ia,pa,l,r; }t[sj*4]; long long lazy[sj*4],len,ans1,ans2,ans3; long long mgcd(long long x,long long y) { if(y==0) return x; return mgcd(y,x%y); } void build(int x,long long z,long long y) { t[x].l=z,t[x].r=y; if(z==y) { t[x].ia=y; t[x].pa=y*y; return; } int mid=(z+y)>>1; build(x<<1,z,mid),build((x<<1)|1,mid+1,y); t[x].ia=t[x<<1].ia+t[(x<<1)|1].ia; t[x].pa=t[x<<1].pa+t[(x<<1)|1].pa; } void pushup(int x) { t[x].aa=t[x<<1].aa+t[(x<<1)|1].aa; t[x].ya=t[x<<1].ya+t[(x<<1)|1].ya; t[x].fa=t[x<<1].fa+t[(x<<1)|1].fa; } void pushdown(int x) { if(lazy[x]) { int ls=x<<1,rs=(x<<1)|1; lazy[ls]+=lazy[x],lazy[rs]+=lazy[x]; len=t[rs].r-t[rs].l+1ll; t[rs].aa+=len*lazy[x],t[rs].ya+=t[rs].ia*lazy[x],t[rs].fa+=t[rs].pa*lazy[x]; len=t[ls].r-t[ls].l+1; t[ls].aa+=len*lazy[x],t[ls].ya+=t[ls].ia*lazy[x],t[ls].fa+=t[ls].pa*lazy[x]; lazy[x]=0; } } void update(int x,long long z,long long y,long long v) { if(t[x].l==z&&t[x].r==y) { lazy[x]+=v; len=y-z+1; t[x].aa+=len*v; t[x].ya+=t[x].ia*v; t[x].fa+=t[x].pa*v; return; } long long mid=(t[x].r+t[x].l)>>1; pushdown(x); if(y<=mid) update(x<<1,z,y,v); if(z>mid) update((x<<1)|1,z,y,v); if(z<=mid&&y>mid) { update(x<<1,z,mid,v); update((x<<1)|1,mid+1,y,v); } pushup(x); } void query(int x,long long z,long long y) { if(t[x].l==z&&t[x].r==y) { ans1=t[x].aa,ans2=t[x].ya,ans3=t[x].fa; return; } long long mid=(t[x].l+t[x].r)>>1; pushdown(x); if(y<=mid) { query(x<<1,z,y); return; } if(z>mid) { query((x<<1)|1,z,y); return; } query(x<<1,z,mid); long long ta1,ta2,ta3; ta1=ans1,ta2=ans2,ta3=ans3; query((x<<1)|1,mid+1,y); ans1+=ta1,ans2+=ta2,ans3+=ta3; } int main() { scanf("%d%d",&n,&m); n--; build(1,1,n); for(int i=1;i<=m;i++) { scanf("%s%lld%lld",&a,&a1,&a2); a2--; if(a=='C') { scanf("%lld",&a3); update(1,a1,a2,a3); } if(a=='Q') { query(1,a1,a2); ans=ans2*(a1+a2)-ans3-(a2+1ll)*(a1-1ll)*ans1; tp=(a2-a1+2)*(a2-a1+1)/2; gcd=mgcd(ans,tp); ans/=gcd; tp/=gcd; printf("%lld/%lld\n",ans,tp); } } return 0; }