2021.04.24【NOIP提高B组】模拟 总结

T1

题意:有一圈数。两两之间有加法或乘法操作,

问你开始断掉那条边使得剩下的序列经过某种操作后的值最大

看上去是个区间 dp 。然后直接断环成列,找最大值。

光荣 WA

原因:负负得正,最小的两个负数相乘可能比最大的要大

所以多维护一个最小值,乘法的时候多考虑几种情况即可

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n,m,x[N],f[N][N],g[N][N],mx,ans[N],len; char ch[5],op[N];
int main() {
scanf("%d",&n),m=n<<1;
for(int i=1;i<=m;i++) {
if(i&1)scanf("%s",ch),op[i+1>>1]=ch[0];
else scanf("%d",&x[i>>1]);
}
for(int i=1;i<=n;i++)x[i+n]=x[i],op[i+n]=op[i];
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
f[i][j]=-1<<16,g[i][j]=1<<16;
for(int i=1;i<=m;i++)f[i][i]=g[i][i]=x[i];
for(int l=2;l<=n;l++)
for(int i=1,j=l;j<=m;i++,j++)
for(int k=i;k<j;k++) {
if(op[k+1]=='t') {
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
g[i][j]=min(g[i][j],g[i][k]+g[k+1][j]);
} else {
f[i][j]=max(f[i][j],max(f[i][k]*f[k+1][j],g[i][k]*g[k+1][j]));
f[i][j]=max(f[i][j],max(f[i][k]*g[k+1][j],g[i][k]*f[k+1][j]));
g[i][j]=min(g[i][j],min(f[i][k]*f[k+1][j],g[i][k]*g[k+1][j]));
g[i][j]=min(g[i][j],min(f[i][k]*g[k+1][j],g[i][k]*f[k+1][j]));
}
}
for(int i=1;i<=n;i++) {
if(f[i][i+n-1]>mx)mx=f[i][i+n-1],ans[len=1]=i;
else if(f[i][i+n-1]==mx)ans[++len]=i;
}
printf("%d\n",mx);
for(int i=1;i<=len;i++)
printf("%d ",ans[i]);
}

T2

题意:问你 \(n\) 条变得正凸多边形恰好划分的 \(n-2\) 个三角形中有 \(k\) 个等腰三角形的方案数

不会

\(Update\)

设 \(f_{i,j,k}\) 为从顶点 \(i\) 到顶点 \(j\) 划分出 \(k\) 个等腰三角形个方案数

可得 \(f_{i,j,k}=\sum f_{i,mid,l}*f_{mid,j,k-l-pd(i,j,mid)}\)

其中 \(pd(a,b,c)\) 为判断 \(S_{\triangle abc}\) 是否为等腰三角形

这样时间为 \(O(n^5)\) 会超时

由于是个正多边形,可以压掉 \(i\) 这一维,设 \(f_{i,k}\) 为从 \(1\) 到 \(i\) 有 \(k\) 个等腰三角形的方案数

有 \(f_{i,k}=\sum f_{j,l}*f_{i-j+1,k-l-pd(1,i,j)}\)

复杂度 \(O(n^4)\) 可以通过

\(TLE\) 方法

#include<bits/stdc++.h>
using namespace std;
const int N=55,P=9397;
int n,m,f[N][N][N],pd;
inline int A(int i,int j) {
return min(abs(i-j),n-abs(i-j));
}
inline void chk(int i,int j,int k) {
pd=0;
if(A(i,j)==A(i,k)||A(i,j)==A(j,k)||A(i,k)==A(j,k))pd=1;
}
int main() {
while(scanf("%d%d",&n,&m)!=EOF) {
memset(f,0,sizeof(f));
for(int i=1;i<=n-1;i++)f[i][i+1][0]=1;
for(int i=1;i<=n-2;i++)f[i][i+2][1]=1;
for(int len=4;len<=n;len++) {
for(int i=1,j=len;j<=n;i++,j++) {
for(int mi=i;mi<=j;mi++) {
for(int k=0;k<=m;k++) {
chk(i,j,mi);
for(int l=0;l<=k-pd;l++)
(f[i][j][k]+=f[i][mi][l]*f[mi][j][k-l-pd]%P)%=P;
}
}
}
}
printf("%d\n",f[1][n][m]);
}
}

\(AC\) 方法

#include<bits/stdc++.h>
using namespace std;
const int N=55,P=9397;
int n,m,f[N][N],pd;
inline int A(int i,int j) {
return min(abs(i-j),n-abs(i-j));
}
inline void chk(int i,int j,int k) {
pd=0;
if(A(i,j)==A(i,k)||A(i,j)==A(j,k)||A(i,k)==A(j,k))pd=1;
}
int main() {
while(scanf("%d%d",&n,&m)!=EOF) {
memset(f,0,sizeof(f));
f[2][0]=1;
for(int i=3;i<=n;i++) {
for(int j=2;j<i;j++) {
chk(1,i,j);
for(int k=pd;k<=m;k++)
for(int l=0;l<=k-pd;l++)
(f[i][k]+=f[j][l]*f[i-j+1][k-l-pd]%P)%=P;
}
}
printf("%d\n",f[n][m]);
}
}

T3

题意:有一个 \(n\) 个点的凸多边形,划分成 \(n-2\) 个面积是 \(S_i\) 的三角形,

问 \(\sqrt{\dfrac{\sum_{i=1}^{n-2}(S_i-\overline{S})^2}{n-2}}\) 的最小值,其中 \(\overline{S}\) 是三角形面积平均值

其实就是求 \(\sum_{i=1}^{n-2}(S_i-\overline{S})^2\) 的最小值

看看对于一个多边形

它的最有方案肯定是选择 一条边,并选择一个点

然后将问题分成左右两个子问题

会发现其实左右也是在原有基础选一个点,然后分成更小的子问题

考虑设 \(f_{i,j}\) 为以直线 \(ij\) 为底作三角形的最小值

变成一个区间 dp

如何确定 dp 的顺序:极角排序。

如何求原有的多边形面积(为了平均值):排完序后, \(\sum_{i=3}^{n} S_{\triangle P_1P_{i-1}P_i}\)

具体点:

写出方程 \(f_{i,j}=\min f_{i,k}+f_{k,j}+(S_{\triangle P_iP_jP_k}-ave)^2\)

然后,切

#include<bits/stdc++.h>
using namespace std;
const int N=55;
typedef double db;
struct poi {
db x,y;
}p[N];
inline bool cmp(poi u,poi v) {
register double A=atan2(u.y-p[1].y,u.x-p[1].x),
B=atan2(v.y-p[1].y,v.x-p[1].x);
return A==B?u.x<v.x:A<B;
}
inline db sqr(db x) { return x*x; }
inline db dis(int i,int j) {
return sqrt(sqr(p[i].x-p[j].x)+sqr(p[i].y-p[j].y));
}
inline db area(db a,db b,db c) {
register db p=(a+b+c)/2.0;
return sqrt(p*(p-a)*(p-b)*(p-c));
}
inline db sum(int i,int j,int k) {
return area(dis(i,j),dis(i,k),dis(j,k));
}
db f[N][N],ave;
int n,k;
int main() {
scanf("%d",&n);
p[0].x=p[0].y=2100000000;
for(int i=1;i<=n;i++) {
scanf("%lf%lf",&p[i].x,&p[i].y);
if(p[0].y>p[i].y || (p[0].y==p[i].y && p[0].x>p[i].x))
p[0]=p[i],k=i;
}
swap(p[1],p[k]);
sort(p+2,p+n+1,cmp);
for(int i=3;i<=n;i++)
ave+=sum(1,i-1,i);
ave/=1.0*n-2;
memset(f,100,sizeof(f));
for(int i=1;i<n-1;i++)f[i][i+2]=sqr(sum(i,i+1,i+2)-ave);
for(int i=1;i<=n;i++)f[i][i+1]=f[i][i]=0;
for(int l=1;l<=n;l++)
for(int i=1,j=l;j<=n;i++,j++)
for(int k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]+sqr(sum(i,j,k)-ave));
printf("%.2lf",sqrt(f[1][n]/(1.0*n-2)));
}

T4

有 \(n\) 个位置在 \(x_i\) 的点,总共能选 \(m\) 个点,选的两个点距离不能小于等于 \(d\)

每选一个点能获得 \([l_i,r_i]\) 的范围,问能获得的最大范围

设 \(f_{i,j}\) 表示第 \(i\) 个选了 \(j\) 的最大值

有 \(f_{1,i}=r_i-l_i\) 和 \(\forall 1<i\le n,f_{i,j}=\max f_{i-1,k}+r_j-\max(l_j,r_k)\)

你会发现,这份 20 分的代码,如果打得好,会得到 40 分,甚至——100分

注意:\(x_{i-1}<x_i,l_{i-1}<l_i\)

考虑对 \(\max\) 分类讨论,开两棵权值线段树,要离散化

第一棵,\(r_s\) 里存着 \(f_{i-1,s}-r_s\) 的最大值

第二棵,\(r_s\) 里存着 \(f_{i-1,s}\) 的最大值

因为 \(x\) 递增,所以对于同一个 \(i\) 下的 \(j\) ,若 \(x_{j-1}-x_k>d\),则 \(x_j-x_k>d\)

可以运用双指针技巧

一开始,现将一些满足 \(x_j-x_k>d\) 的 \(k\) 放进树中

查询第一棵树中 \([l_j+1,2n]\) 的最大值(因为离散化,所以要乘 2)

和第二棵树中 \([1,l_j]\) 的最大值

然后计算 \(f_{i,j}\) 即可

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
struct seg {
#define ls rt<<1
#define rs rt<<1|1
int mx[N<<4];
void bui(int l,int r,int rt) {
mx[rt]=-2100000000;
if(l==r)return;
register int mid=l+r>>1;
bui(l,mid,ls);
bui(mid+1,r,rs);
}
void mdy(int p,int v,int l,int r,int rt) {
if(l==r) { mx[rt]=max(mx[rt],v); return; }
register int mid=l+r>>1;
if(p<=mid)mdy(p,v,l,mid,ls);
else mdy(p,v,mid+1,r,rs);
mx[rt]=max(mx[ls],mx[rs]);
}
int ask(int ql,int qr,int l,int r,int rt) {
if(ql<=l && r<=qr)return mx[rt];
if(ql>r || l>qr)return -2100000000;
register int mid=l+r>>1;
return max(ask(ql,qr,l,mid,ls),ask(ql,qr,mid+1,r,rs));
}
#undef ls
#undef rs
}LL,RR; int n,m,D,x[N],L[N],R[N],k,t[N]; int f[N][N],ans;
inline bool cmp(int x,int y) {
return R[x]<R[y];
}
int main() {
scanf("%d%d%d",&n,&m,&D);
for(int i=1;i<=n;i++) {
scanf("%d%d%d",&x[i],&L[i],&R[i]);
f[1][i]=R[i]-L[i];
t[++k]=L[i],t[++k]=R[i];
}
sort(t+1,t+k+1);
k=unique(t+1,t+k+1)-t-1;
for(int i=1;i<=n;i++) {
L[i]=lower_bound(t+1,t+k+1,L[i])-t;
R[i]=lower_bound(t+1,t+k+1,R[i])-t;
}
for(int i=2,k,p,q;i<=m;i++) {
LL.bui(1,n*2,1);
RR.bui(1,n*2,1);
k=1;
for(int j=1;j<=n;j++) {
for(;x[j]-x[k]>D && k<=n;k++) {
LL.mdy(R[k],f[i-1][k],1,n*2,1);
RR.mdy(R[k],f[i-1][k]-t[R[k]],1,n*2,1);
}
p=LL.ask(1,L[j],1,n*2,1);
q=RR.ask(L[j]+1,n*2,1,n*2,1);
f[i][j]=f[i-1][j];
if(k>1)f[i][j]=max(f[i][j],max(p-t[L[j]],q)+t[R[j]]);
ans=max(ans,f[i][j]);
}
}
printf("%d",ans);
}

总结

  1. 长知识了
  2. 新的区间 dp 模板
  3. 极角排序运用
  4. 如何暴力+线段树优化

2021.04.24【NOIP提高B组】模拟 总结的更多相关文章

  1. JZOJ 5818. 【NOIP提高A组模拟2018.8.15】 做运动

    5818. [NOIP提高A组模拟2018.8.15] 做运动 (File IO): input:running.in output:running.out Time Limits: 2000 ms  ...

  2. 5820. 【NOIP提高A组模拟2018.8.16】 非法输入(模拟,字符串)

    5820. [NOIP提高A组模拟2018.8.16] 非法输入 (File IO): input:aplusb.in output:aplusb.out Time Limits: 1000 ms   ...

  3. JZOJ 5812. 【NOIP提高A组模拟2018.8.14】 区间

    5812. [NOIP提高A组模拟2018.8.14] 区间 (File IO): input:range.in output:range.out Time Limits: 1000 ms  Memo ...

  4. 2021.05.04【NOIP提高B组】模拟 总结

    T1 题目大意, \(S_{i,j}=\sum_{k=i}^j a_k\) ,求 \(ans=\min\{ S_{i,j}\mod P|S_{i,j}\mod P\ge K \}\) 其中 \(i\l ...

  5. [JZOJ5818] 【NOIP提高A组模拟2018.8.15】 做运动

    Description 一天,Y 君在测量体重的时候惊讶的发现,由于常年坐在电脑前认真学习,她的体重有了突 飞猛进的增长. 幸好 Y 君现在退役了,她有大量的时间来做运动,她决定每天从教学楼跑到食堂来 ...

  6. [JZOJ5817] 【NOIP提高A组模拟2018.8.15】 抄代码

    Description J 君是机房的红太阳,每次模拟她总是 AK 虐场.然而在 NOIP2117 中,居然出现了另一位 AK 的选手 C 君! 这引起了组委会的怀疑,组委会认为 C 君有抄袭 J 君 ...

  7. 【NOIP提高A组模拟2018.8.14】 区间

    区间加:差分数组修改 O(n)扫描,负数位置单调不减 #include<iostream> #include<cstring> #include<cstdio> # ...

  8. [jzoj 5782]【NOIP提高A组模拟2018.8.8】 城市猎人 (并查集按秩合并+复杂度分析)

    传送门 Description 有n个城市,标号为1到n,修建道路花费m天,第i天时,若gcd(a,b)=m-i+1,则标号为a的城市和标号为b的城市会建好一条直接相连的道路,有多次询问,每次询问某两 ...

  9. [jzoj 5781]【NOIP提高A组模拟2018.8.8】秘密通道 (最短路)

    传送门 Description 有一副nm的地图,有nm块地,每块是下列四种中的一种: 墙:用#表示,墙有4个面,分别是前面,后面,左面,右面. 起点:用C表示,为主角的起点,是一片空地. 终点:用F ...

  10. [jzoj 5778]【NOIP提高A组模拟2018.8.8】没有硝烟的战争 (博弈论+dp)

    传送门 Description 被污染的灰灰草原上有羊和狼.有N只动物围成一圈,每只动物是羊或狼. 该游戏从其中的一只动物开始,报出[1,K]区间的整数,若上一只动物报出的数是x,下一只动物可以报[x ...

随机推荐

  1. Springcloud报错:java.lang.IllegalStateException: Service id not legal hostname (/a-service)

    今天在做springcloud链路追踪的时候,报错java.lang.IllegalStateException: Service id not legal hostname (/a-service) ...

  2. C# 将PDF转为Excel

    通常,PDF格式的文档能支持的编辑功能不如office文档多,针对PDF文档里面有表格数据的,如果想要编辑表格里面的数据,可以将该PDF文档转为Excel格式,然后编辑.本文,将以C#代码为例,介绍如 ...

  3. Struts2-值栈的定义

    1.值栈的概念:在Struts2里面提供本身的一种储存机制,类似于域对象,可以存值和取值(可以类比Servlet中的域对象->request,session,application) 2.具体操 ...

  4. zabbix使用自带模板监控MySQL

    监控mysql不能直接使用zabbix自带模板,还需要到被监控的mysql客户端做配置. 1.在zabbix   web配置步骤如下图: 2.配置完之后去看mysql主机监控项的时候看到mysql的监 ...

  5. Linux内核--链表结构(一)

    一.前言 Linux内核链表结构是一种双向循环链表结构,与传统的链表结构不同,Linux内核链表结构仅包含前驱和后继指针,不包含数据域.使用链表结构,仅需在结构体成员中包含list_head*成员就行 ...

  6. NodeJs学习日报day6——路由模块

    const express = require('express') const app = express() app.get('/user', function(req, resp) { resp ...

  7. SpringCloud分布式尝试记录

    服务提供端: 客户消费端:

  8. docker基础_docker镜像与分层

    docker镜像与分层 docker镜像由一些松耦合的制度镜像层组成 docker负责堆叠这些镜像层并将它们表示为单个统一的对象 当 docker image pull ubuntu:latest 时 ...

  9. LVM从VG中删除PV及删除未知PV

    当我们的硬盘发被删除掉了,我们的PV卷会变成[unknown] 一.首先我们要备份我们的文件,然后再删除lv分区 二. VG中去除PV unknown device:

  10. 详解MySQL索引

    原文链接详解MySQL索引 索引介绍 索引是帮助MySQL高效获取数据的数据结构.在数据之外,数据库系统还维护着一个用来查找数据的数据结构,这些数据结构指向着特定的数据,可以实现高级的查找算法. 本文 ...