T1 交通

解题思路

把环视为点,对于原图中每一个点的两条入边以及两条出边分别连边。

优于保证了原图中每个点出入度都是 2 因此新图中一定由若干个偶数环所组成的。

并且对于环中一定是只能间隔着选点,因此每个环有 2 种选择,答案就是 \(2^{环数}\)

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
int n,ans,in[N][2],out[N][2],t1[N],t2[N],fa[N<<1];
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
int power(int x,int y)
{
int temp=1;
while(y)
{
if(y&1) temp=temp*x%mod;
x=x*x%mod; y>>=1;
}
return temp;
}
signed main()
{
freopen("a.in","r",stdin); freopen("a.out","w",stdout);
n=read();
for(int i=1,x,y;i<=2*n;i++)
{
fa[i]=i; x=read(); y=read();
in[y][t1[y]++]=i; out[x][t2[x]++]=i;
}
for(int i=1;i<=n;i++)
{
if(find(in[i][0])!=find(in[i][1])) fa[find(in[i][0])]=find(in[i][1]);
if(find(out[i][0])!=find(out[i][1])) fa[find(out[i][0])]=find(out[i][1]);
}
for(int i=1;i<=2*n;i++) ans+=(find(i)==i);
printf("%lld",power(2,ans)%mod);
return 0;
}

T2 小P的单调数列

解题思路

\(n^3\) 的 DP 比较好想, \(f_{i,j}\) 表示默认选择第 \(i\) 个并且当前段数为 \(j\) 个的情况直接暴力枚举当前个,前一个,以及对应段数就好了。

可以发现只选择一个最长上升子序列和一个最长下降子序列其实是最优的方案,因为如果再加入一段序列答案会变优的情况只能是新加入序列比上升段或者下降段的总和更大的时候。。

这种情况显然是不存在的,时间复杂度降到 \(n^2\) 在加上棵线段树就可以达到 \(nlogn\) 的复杂度了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e5+10,INF=1e18;
int n,cnt,lsh[N],s[N];
double ans;
struct Segment_Tree
{
int tre[N<<2];
void push_up(int x){tre[x]=max(tre[ls],tre[rs]);}
void insert(int x,int l,int r,int pos,int val)
{
if(l==r) return tre[x]=max(tre[x],val),void();
int mid=(l+r)>>1;
if(pos<=mid) insert(ls,l,mid,pos,val);
else insert(rs,mid+1,r,pos,val);
push_up(x);
}
int query(int x,int l,int r,int L,int R)
{
if(L>R) return -INF;
if(L<=l&&r<=R) return tre[x];
int mid=(l+r)>>1,maxn=-INF;
if(L<=mid) maxn=max(maxn,query(ls,l,mid,L,R));
if(R>mid) maxn=max(maxn,query(rs,mid+1,r,L,R));
return maxn;
}
}T[3];
signed main()
{
freopen("b.in","r",stdin); freopen("b.out","w",stdout);
n=read(); for(int i=1;i<=n;i++) lsh[i]=s[i]=read();
sort(lsh+1,lsh+n+1); cnt=unique(lsh+1,lsh+n+1)-lsh-1;
for(int i=1;i<=n;i++) s[i]=lower_bound(lsh+1,lsh+cnt+1,s[i])-lsh;
for(int i=1;i<=n;i++)
for(int k=2;k>=1;k--)
{
if(k==1) T[1].insert(1,1,cnt,s[i],lsh[s[i]]),ans=max(ans,(1.0*lsh[s[i]])/(1.0*k));
int temp=T[k-1].query(1,1,cnt,s[i],s[i]);
if(k&1) temp=max(temp,max(T[k].query(1,1,cnt,1,s[i]-1),T[k-1].query(1,1,cnt,s[i]+1,cnt)));
else temp=max(temp,max(T[k-1].query(1,1,cnt,1,s[i]-1),T[k].query(1,1,cnt,s[i]+1,cnt)));
T[k].insert(1,1,cnt,s[i],temp+lsh[s[i]]);
ans=max(ans,1.0*(1.0*temp+1.0*lsh[s[i]])/(1.0*k));
}
printf("%.3lf",ans);
return 0;
}

T3 矩阵

解题思路

其实我们只要考虑如何消掉前两行和前两列就好了(证明就。。)

假设矩阵数组是 \(s\) 那么先把 \(s_{1,1}\) 和 \(s_{2,2}\) 搞成相同的,接下来对于前两行,我们肯定是先把他们每一列都消成一样的最后再统一干掉。

那么我们已经确定了 \(s_{2,2}\) 就可以对应确定 \(s_{1,2}\) 相应的 \(s_{2,3}\) 也被确定了,以此类推,最后一个可以直接更改。

对于两列的情况也是相同的方法

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e3+10;
int n,m,cnt,s[N][N];
struct Node{int opt,x,dat;}q[N*6];
void check(){cout<<"Check: "<<cnt<<endl;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)cout<<s[i][j]<<' ';cout<<endl;}}
signed main()
{
freopen("c.in","r",stdin); freopen("c.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
s[i][j]=read();
if(n==1){cout<<m<<endl;for(int i=1;i<=m;i++)printf("2 %lld %lld\n",i,-s[1][i]);exit(0);}
if(m==1){cout<<n<<endl;for(int i=1;i<=n;i++)printf("1 %lld %lld\n",i,-s[i][1]);exit(0);}
if(s[1][1]!=s[2][2])
{
int temp=s[2][2]-s[1][1];
q[++cnt]=(Node){1,1,temp};
for(int i=1;i<=m;i++) s[1][i]+=temp;
}
for(int i=2;i<m;i++)
if(s[1][i]!=s[2][i])
{
int temp=s[2][i]-s[1][i];
q[++cnt]=(Node){3,i-1,temp};
for(int x=1,y=i;x<=n&&y<=m;x++,y++)
s[x][y]+=temp;
}
if(s[1][m]!=s[2][m])
{
q[++cnt]=(Node){3,m-1,s[2][m]-s[1][m]};
s[1][m]=s[2][m];
}
for(int i=2;i<n;i++)
if(s[i][1]!=s[i][2])
{
int temp=s[i][2]-s[i][1];
q[++cnt]=(Node){3,1-i,temp};
for(int x=i,y=1;x<=n&&y<=m;x++,y++)
s[x][y]+=temp;
}
if(s[n][1]!=s[n][2])
{
q[++cnt]=(Node){3,1-n,s[n][2]-s[n][1]};
s[n][1]=s[n][2];
}
for(int i=1;i<=m;i++)
if(s[1][i])
{
q[++cnt]=(Node){2,i,-s[1][i]};
for(int j=n;j>=1;j--)
s[j][i]-=s[1][i];
}
for(int i=1;i<=n;i++)
if(s[i][1])
{
q[++cnt]=(Node){1,i,-s[i][1]};
for(int j=m;j>=1;j--)
s[i][j]-=s[i][1];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(s[i][j])
printf("-1"),exit(0);
printf("%lld\n",cnt);
for(int i=1;i<=cnt;i++) printf("%lld %lld %lld\n",q[i].opt,q[i].x,q[i].dat);
return 0;
}

T4 花瓶

解题思路

斜率优化 DP

\(f_{i,j}\) 表示当前到 \(i\) 之前的端的右端点是 \(j\) 的最优解, \(s_i\) 表示前缀和

\[f_{i,j}=\max\limits_{0\le k<j}\{f_{j,k}+(s_i-s_j)(s_j-s_k)\}
\]
\[f_{i,j}=(s_i-s_j)s_j+\max\limits_{0\le k<j}\{f_{j,k}-(s_i-s_j)s_k\}
\]

对于 \(s_a<s_b\) 并且 \(b\) 优于 \(a\) 就有:

\[\dfrac{f_{j,a}-f_{j,b}}{s_a-s_b}>(s_i-s_j)
\]

因此我们可以枚举原序列的 \(j\) 并且对于按照 \(s\) 排完序后按照 \(s\) 从大到小进行枚举 \(i\) 。

并且对于每一次的标号小于 \(j\) 的维护出一个上凸包,枚举 \(i\) 的时候更新答案就好了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=5e3+10;
int INF,n,ans,q[N],a[N],f[N][N],pre[N];
struct Node
{
int id,dat;
bool friend operator < (Node x,Node y)
{
if(x.dat==y.dat) return x.id<y.id;
return x.dat<y.dat;
}
}s[N];
signed main()
{
freopen("d.in","r",stdin); freopen("d.out","w",stdout);
n=read(); memset(f,0x8f,sizeof(f)); INF=f[0][0];
for(int i=1;i<=n;i++) a[i]=read(),pre[i]=s[i].dat=s[i-1].dat+a[i],f[i][0]=f[i][i]=0,s[i].id=i;
sort(s+0,s+n+1);
for(int j=1;j<=n;j++)
{
int head=1,tail=0;
for(int i=0;i<=n;i++)
{
if(s[i].id>=j) continue;
while(head<tail&&(f[j][s[i].id]-f[j][s[q[tail]].id])*(s[q[tail]].dat-s[q[tail-1]].dat) >= (f[j][s[q[tail]].id]-f[j][s[q[tail-1]].id])*(s[i].dat-s[q[tail]].dat) )tail--;
q[++tail]=i;
}
for(int i=n;i>=0;i--)
{
if(s[i].id<=j) continue;
while(head<tail&&(f[j][s[q[head]].id]-f[j][s[q[head+1]].id])<(s[i].dat-pre[j])*(s[q[head]].dat-s[q[head+1]].dat)) head++;
f[s[i].id][j]=max(f[s[i].id][j],(s[i].dat-pre[j])*pre[j]+f[j][s[q[head]].id]-(s[i].dat-pre[j])*s[q[head]].dat);
}
}
for(int i=0;i<=n;i++) ans=max(ans,f[n][i]); printf("%lld",ans);
return 0;
}

NOIP模拟61的更多相关文章

  1. Noip模拟61 2021.9.25

    T1 交通 考场上想了一个$NPC$.应该吧,是要求出图里面的所有可行的不重复欧拉路 无数种做法都无法解出,时间也都耗在这个上面的,于是就考的挺惨的 以后要是觉得当前思路不可做,就试着换一换思路,千万 ...

  2. 2021.9.25考试总结[NOIP模拟61]

    终于有点阳间题了然而挂了60pts 哈哈 T1 交通 类似简单题,限制看似很复杂,但不难发现当确定一条边是否被删后会产生裙带关系,很多边会跟着自动被确定是否被删. 仔细观察可以得出这种关系会构成偶环结 ...

  3. NOIP模拟17.9.22

    NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥

  4. NOIP 模拟4 T2

    本题属于二和一问题 子问题相互对称 考虑对于问题一:知a求b 那么根据b数组定义式 显然能发现问题在于如何求dis(最短路) 有很多算法可供选择 dijsktra,floyed,bfs/dfs,spf ...

  5. noip模拟32[好数学啊]

    noip模拟32 solutions 真是无语子,又没上100,无奈死了 虽然我每次都觉得题很难,但是还是有好多上100的 战神都200多了,好生气啊啊啊 从题开始变难之后,我的时间分配越来越不均匀, ...

  6. 2021.9.17考试总结[NOIP模拟55]

    有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...

  7. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  8. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  9. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  10. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

随机推荐

  1. docker containerd runc containerd-shim等组件的关系

    早期 kubelet 创建容器工作原理 因为 docker 出生的比 k8s 早,所以 k8s 早期的容器运行时都是基于 docker 的,kubelet 通过 docker 的 api 创建容器.后 ...

  2. 【pytorch学习】之微积分

    4 微积分 在2500年前,古希腊人把一个多边形分成三角形,并把它们的面积相加,才找到计算多边形面积的方法.为了求出曲线形状(比如圆)的面积,古希腊人在这样的形状上刻内接多边形.如图所示,内接多边形的 ...

  3. 【SIGIR 2022】面向长代码序列的Transformer模型优化方法,提升长代码场景性能

    简介: 论文主导通过引入稀疏自注意力的方式来提高Transformer模型处理长序列的效率和性能 阿里云机器学习平台PAI与华东师范大学高明教授团队合作在SIGIR2022上发表了结构感知的稀疏注意力 ...

  4. 入选 SIGMOD2021 的时间序列多周期检测通用框架 RobustPeriod 如何支撑阿里业务场景?

    简介: 本文除了介绍RobustPeriod的核心技术亮点,还将重点解释如何将它构筑成服务来解决阿里云的业务痛点. 近日,由阿里云计算平台和阿里云达摩院合作的时序多周期检测相关论文RobustPeri ...

  5. [Py] Jupyter 写入和执行 python 文件

    以 %%writefile request.py 开头. 下面写 python 代码,然后 shift + enter 键,可以把 python 代码写入开头指定的文件中,没有则自动创建. 以 %ru ...

  6. JavaScript数组Array方法介绍,使用示例及ES6拓展

    数组定义 有次序和编号的一组值 类似数组对象 函数agruments对象,字符串,DOM元素集 实例属性 Array.prototype.length length可以赋值,用以改变数组长度 arr. ...

  7. OLAP系列之分析型数据库clickhouse集群扩缩容(四)

    一.集群缩容 1.1 下线节点 步骤:1.对外停止服务2.转移数据3.修改剩余节点配置4.通知客户端修改节点列表 # 修改90,91服务器配置文件 vim /etc/clickhouse-server ...

  8. Django之ajax简介

    1.MTV与MVC 框架类型:MVC: M:models V:views C:controller Django用的框架就是MTV MTV: M:models T:templates V:views ...

  9. 在鼠标右键菜单中新增新建Markdown文件选项(VSCode)

    引言 正常情况下,我们新建md文件有两种方式:一是通过Markdown编辑器新建,二是新建txt文件再修改后缀. 但是在Windows系统中,我们可以通过修改注册表来新增右键菜单选项.这里我们可以通过 ...

  10. postgresql的insert语句中进行判断,数据已有则更新,数据没有则插入

    INSERT 操作 INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...); 下面是一个示例: INSE ...