[BZOJ1911][BZOJ1912][BZOJ1913]APIO2010解题报告
2015-05-09 11:37
459 查看
特别行动队
Description
这个好像斜率优化不是一般地明显了啊...只不过要分a的正负两种情况考虑是维护上凸还是下凸
/************************************************************** Problem: 1911 User: mjy0724 Language: C++ Result: Accepted Time:1688 ms Memory:24248 kb ****************************************************************/ #include<cstdio> #include<cstdlib> #include<cstring> const int maxn=1000010;long long INF=10000000000000007; long long n,a,b,c,sum[maxn],opt[maxn],f[maxn]; long long g(int j,int k){ if (2*a*(sum[j]-sum[k])==0) { if (f[j]+a*sum[j]*sum[j]-b*sum[j]-(f[k]+a*sum[k]*sum[k]-b*sum[k])>0) return INF; else return -INF; } return (f[j]+a*sum[j]*sum[j]-b*sum[j]-(f[k]+a*sum[k]*sum[k]-b*sum[k]))/(2*a*(sum[j]-sum[k])); } int main(){ scanf("%lld",&n); scanf("%lld%lld%lld",&a,&b,&c); for (int i=2;i<=n+1;i++) scanf("%lld",&sum[i]),sum[i]+=sum[i-1]; int head=1,tail=1;opt[1]=1;f[1]=0; for (int i=2;i<=n+1;i++){ if (a>=0) while (head<tail&&g(opt[head],opt[head+1])>sum[i]) head++; else while (head<tail&&g(opt[head],opt[head+1])<sum[i]) head++; int j=opt[head]; f[i]=f[j]+a*(sum[i]-sum[j])*(sum[i]-sum[j])+b*(sum[i]-sum[j])+c; if (a>=0) while (head<tail&&g(opt[tail-1],opt[tail])<g(opt[tail],i)) tail--; else while (head<tail&&g(opt[tail-1],opt[tail])>g(opt[tail],i)) tail--; opt[++tail]=i; } printf("%lld\n",f[n+1]); return 0; }
patrol 巡逻
Description
首先对于k=1的情况,稍微观察就可以看出来,假设连上这条边之后原图形成了一个由n个点组成的环
原先经过这些点的边数为2(n-1),如今为n,所以减少的路径为(n-2)
如果是再连一条边的话,如果不与第一条形成的环相交(指有边重合),那么显然规律不变
如果有边重叠了,设重叠的边数为x,那么原先经过这些点的边数为2(n--1-x),如今为n,所以减少的路径为n-2-2x
也就是相对于第一种规律,每重叠一条边,减少的路径数-2
那么我们不妨令每条边初始边权为1,第一问可以通过求树的直径得到
对于第一问经过的路径,边权改为-1,也就实现了每重叠一条边,减少的路径数-2的效果
/************************************************************** Problem: 1912 User: mjy0724 Language: C++ Result: Accepted Time:708 ms Memory:5288 kb ****************************************************************/ #include<cstdio> #include<cstdlib> #include<cstring> const int maxn=100010,maxm=200010; int n,k,e,link[maxn],next[maxm],fa[maxm],pos1[maxn],pos2[maxn],w[maxm],ans,sum,s; void add(int x,int y){ fa[++e]=y;next[e]=link[x];link[x]=e;w[e]=1; fa[++e]=x;next[e]=link[y];link[y]=e;w[e]=1; } int dfs(int p,int fat){ int max1=0,max2=0; for (int i=link[p];i;i=next[i]) if (fa[i]!=fat){ int tmp=dfs(fa[i],p)+w[i]; if (tmp>max1){ max2=max1;max1=tmp;pos2[p]=pos1[p];pos1[p]=i; }else if (tmp>max2) max2=tmp,pos2[p]=i; } if (max1+max2>ans) { ans=max1+max2;s=p; } return max1; } int main(){ scanf("%d%d",&n,&k); int e=0,x,y; for (int i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y); dfs(1,0);sum=ans; if (k==1){printf("%d\n",2*(n-1)-(ans-1));return 0;} for (int i=pos1[s];i;i=pos1[fa[i]]) w[i]=-1; for (int i=pos2[s];i;i=pos1[fa[i]]) w[i]=-1; ans=0;dfs(1,0); printf("%d\n",2*(n-1)-(ans-1)-(sum-1)); return 0; }
signaling 信号覆盖
Description
我们考虑四边形
如果是凸的四边形,当对角和>180度的时候能够信号覆盖4个,也就是一个凸四边形能带来2种答案为4的取法
凹多边形只要取外面的3个点可以带来1种答案为4的取法 剩下的情况答案都为3
凹多边形的取法与凸多边形的取法是已知一个可以计算出另一个的
于是我们可以先考虑计算凹多边形的取法
先枚举位于中间的点,容易看出,剩下三个点构成的三角形能够包含中间点
相反的,不能包含的就是不能构成凹多边形的,于是我们可以计算这些不包含的方案数
对所有的点按照中间点进行极角排序,然后单调队列维护每个点能够到达的最远点,使得两点间的所有点的极角差都在180度之间
可以用叉积简化运算
最后注意一些乘法加法运算的细节就可以了
/************************************************************** Problem: 1913 User: mjy0724 Language: C++ Result: Accepted Time:1996 ms Memory:1356 kb ****************************************************************/ #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #define ll long long #define maxn 1510 struct point{ ll x,y; double angle; }; ll n,an,b; point p[maxn],a[maxn]; ll cross(point p0,point p1,point p2){ return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); } void sortf(int l,int r){ int i=l,j=r;double mid=p[(l+r) >> 1].angle; do{ while (i<r&&p[i].angle<mid) i++; while (l<j&&p[j].angle>mid) j--; if (i<=j){ point tmp=p[i];p[i]=p[j];p[j]=tmp; i++;j--; } }while (i<=j); if (i<r) sortf(i,r); if (l<j) sortf(l,j); } ll calc(int x){ int tot=0; for (int i=1;i<=n;i++) {if (i!=x) p[++tot]=a[i];else p[0]=a[i];} for (int i=1;i<=tot;i++) p[i].angle=atan2(p[i].y-p[0].y,p[i].x-p[0].x); sortf(1,tot); ll ans=(n-1)*(n-2)*(n-3)/6; ll tail=2,t=0; for (int i=1;i<=tot;i++){ while (cross(p[0],p[i],p[tail])>=0) {tail=tail%tot+1;t++;if (tail==i) break;} ans-=t*(t-1)/2;t--; } return ans; } int main(){ scanf("%lld",&n); for (int i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].y); ll an=0;for (int i=1;i<=n;i++) an+=calc(i); ll b=n*(n-3)*(n-2)*(n-1)/24-an,c=2*b+an,d=(n-2)*n*(n-1)/6; printf("%lf",(double)(c*4+(d-c)*3)/d); return 0; }
相关文章推荐
- 斜率优化专题4——bzoj 1911: [Apio2010] 特别行动队 题解
- bzoj 1911 [Apio2010]特别行动队斜率优化+DP
- bzoj 1912 [Apio2010]patrol 巡逻 树形dp
- [BZOJ 1913][Apio2010]signaling 信号覆盖:计算几何
- BZOJ 1911 [Apio2010]特别行动队(单调队列优化DP)
- bzoj 1911: [Apio2010]特别行动队(斜率优化)
- bzoj1911 [Apio2010]特别行动队
- [BZOJ1912][Apio2010]patrol 巡逻(树上最长链)
- bzoj 1911 [Apio2010]特别行动队(斜率优化+DP)
- BZOJ 1821 [JSOI 2010] 最小生成树 解题报告
- 【bzoj1913】 Apio2010—signaling 信号覆盖
- BZOJ1911 [Apio2010]特别行动队 斜率优化
- BZOJ 2005 [Noi 2010] 数论 解题报告
- 【bzoj1911】 Apio2010—特别行动队
- BZOJ 1911: [Apio2010]特别行动队 [斜率优化dp]
- 【BZOJ 1912】 [Apio2010]patrol 巡逻
- _bzoj1911 [Apio2010]特别行动队【斜率优化dp】
- 【BZOJ1911】【Apio2010】特别行动队,斜率优化DP裸题(斜率有单调性)
- BZOJ 1911: [Apio2010]特别行动队(斜率优化+DP)
- BZOJ 1911 [Apio2010]特别行动队