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. 重新整理 .net core 实践篇————防跨站脚本攻击[四十]

    前言 简单整理一下跨站脚本攻击. 正文 攻击原理是这样子的: 这种攻击被攻击的面挺多的,比如说只要有一个可以让用户输入的注入脚本就都是一个问题. 给网站注入脚本 然后用户访问给网站注入的脚本 脚本里面 ...

  2. .gitignore 基础

    前言 gitignore文件有几种方式生成. 1.在创建版本库的时候生成. 2.自己手动添加: windows环境下,不能把文件直接改名为.gitignore,会提示你必须输入文件名.所以我们先新建一 ...

  3. Scratch3之AI集成 - flappy bird AI版本

    AI神秘且有趣,我们一个经典的游戏flappy bird集成AI,实现自训练成长的聪明的笨鸟.先上效果: 初始化的笨鸟拥有分身,每个分身都有自我学习功能,根据自己的移动轨迹和得分情况进行汇总,进行新一 ...

  4. springboot+thymeleaf+mybatis实现甘特图(代码非常详细)

    首先我们要明白:这个甘特图需要哪些动态数据. (1)需要:ID,tName,number,计划开始时间,开始时间,计划结束时间,结束时间,项目负责人,参与人,知情人ID,计划时长(可以计算得出的,不必 ...

  5. 《c#高级编程》第4章C#4.0中的更改(六)——动态绑定

    一.概念 下面是一些代码示例,说明C#动态绑定的上述特点: 1. 延迟确定类型 ```dynamic obj = GetDynamicObject(); // 获取动态对象obj.DoSomethin ...

  6. 第三課:信道学习Source Connect Reader & Destinations File Writer

    第一步: 切换到主信道(Channels)界面,右键点击新建信道(New Channel) 第二步 : 下面是设置一些信道概要(Summary)信息 其中summary(概要) 界面主要包含 信道名称 ...

  7. Dubbo Mesh:从服务框架到统一服务控制平台

    简介: Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java.Golang 等多语言 SDK 实现. 作者:Dubbo 社区   Ap ...

  8. 表格存储 SQL 查询多元索引

    ​简介: 多元索引是表格存储产品中一个重要的功能,多元索引使用倒排索引技术为表格存储提供了非主键列上的快速检索功能,另外也提供了统计聚合功能.表格存储近期开放了SQL查询功能,SQL引擎默认从原始表格 ...

  9. Solution Set - 点分治

    A[POJ1741].给定一棵树,边有权,求长度不超过\(k\)的路径数目. B[HDU4871].给定一张图,边有权,求它的最短路径树上恰含\(k\)个点的路径中最长路径的长度及数目. C[HDU4 ...

  10. 视频讲解如何构建surging微服务调用

    surging 是一款优秀的微服务引擎,包括了社区版,标准版,异构版,平台版本来解决公司的业务场景需求,如果你是初学者,或者是技术狂热者,社区版完全可以符合你们的要求来学习或者构建起微服务体系的引擎框 ...