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. mysql 必知必会整理—sql 排序与过滤[三]

    前言 简单整理一下MySQL的排序与过滤. 正文 我们查询出来的结果有时候是希望进行排序的,比如说: select product_name from products order by prod_n ...

  2. 重新整理数据结构与算法(c#)—— 平衡二叉树[二十三]

    前言 因为有些树是这样子的: 这样子的树有个坏处就是查询效率低,因为左边只有一层,而右边有3层,这就说明如果查找一个数字大于根元素的数字,那么查询判断就更多. 解决方法就是降低两边的层数差距: 变成这 ...

  3. chrome浏览器代理插件SwitchyOmega使用

    第一步:下载SwitchyOmega插件 Proxy_SwitchyOmega_2.5.21.crx 第二步:安装插件, 1,在chrome扩展程序开启开发者模式: 2,将插件拖过来: 第三步:设置代 ...

  4. vue项目中嵌入软键盘(中文/英文)

    键盘效果是这样,样式可以自己调整.gittee地址:https://gitee.com/houxianzhou/VirtualKeyboard.git步骤1 安装使用jQuery npm instal ...

  5. bs4、selenium的使用

    爬取新闻 # 1 爬取网页---requests # 2 解析 ---xml格式,用了re匹配的 ---html,bs4,lxml... ---json: -python :内置的 -java : f ...

  6. css添加属性,让浏览器检查无法选中元素

    1.表现 浏览器直接选中元素的时候,仅能直接选中整个body,想要找到具体元素,需要自己手动寻找,没太大实际作用,仅仅让不懂的人不能简简单单的直接定位元素然后修改里面的内容 pointer-event ...

  7. 牛客网-SQL专项训练16

    ①在book表中,将工具书类型(tool)的书的书架序号都减少2,下列语句正确的是(C) 解析: 题目要求的批量更改,insert 是更改数据,排除B,update与set搭配使用,排除选项D,whe ...

  8. 云原生时代如何用 Prometheus 实现性能压测可观测-Metrics 篇

    ​简介:可观测性包括 Metrics.Traces.Logs3 个维度.可观测能力帮助我们在复杂的分布式系统中快速排查.定位问题,是分布式系统中必不可少的运维工具. 作者:拂衣 什么是性能压测可观测 ...

  9. 在阿里巴巴,我们如何先于用户发现和定位 Kubernetes 集群问题?

    ​简介:本文整理自阿里云高级研发工程师彭南光(光南) 在 KubeCon China 2021 大会的演讲实录,分享了阿里巴巴是如何通过自研通用链路探测+定向巡检工具 KubeProbe 应对大规模集 ...

  10. 函数计算 GB 镜像秒级启动:下一代软硬件架构协同优化揭秘

    ​简介:本文将介绍借助函数计算下一代 IaaS 底座神龙裸金属和安全容器,进一步降低绝对延迟且能够大幅降低冷启动频率. 作者:修踪 背景 函数计算在 2020 年 8 月创新地提供了容器镜像的函数部署 ...