T1 旋转子段

30% 暴力枚举起点和长度,暴力判断,o(n3)  不知道为什么我拿了40分。。。

60% 每一个点都有一个固定的旋转中心可以转成固定点,枚举旋转点和长度。

100% 用一个vector存一下以此点为旋转中心,可以将哪些点转成好点,存区间的左右端点(i,a[i]),将区间长度从小到大排序,枚举中间点,再枚举以他为中心可以将哪些点转成固定点,由于按区间长度排序了,所以第几个点+1就是旋转后当前区间有的固定点个数。区间左右的用前缀和计算即可。

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int n,ans,a[],q[];
vector< pair<int,int> >ve[];
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
q[i]=q[i-];
if(a[i]==i) q[i]++;
ve[a[i]+i].push_back(make_pair(max(a[i],i),min(a[i],i)));
}
if(q[n]==n){
printf("%d\n",n);
return ;
}
for(int i=;i<=*n;i++){
sort(ve[i].begin(),ve[i].end());
for(int j=;j<ve[i].size();j++){
int r=ve[i][j].first,l=ve[i][j].second;
ans=max(ans,j++q[l-]+q[n]-q[r]);
}
}
printf("%d\n",ans);
}

旋转子段

T2 走格子

将网格抽象成图,建边,跑dj或spfa。知道建边就好做了,可是我想不到。。。。

需要建的边 一种是空格和空格之间的  一种是穿墙。

第一种直接暴力建就行了。第二种找到离空格最近的墙,到其他墙前的空格的步数为 最近墙+1

最近的墙可以lowerbound二分查找,也可以bfs:从墙往空地扩展,dis[][]中存的就是到最近墙的距离,具体是哪面不重要。

每个空地穿墙后到达的空地,可以o(n×m)扫一遍,他就挨着墙,那么他的位置就是答案,其他的只需要继承前一个的就行。

穿墙到达空地这时需要建单向边,因为从这个空能到这面墙前,这面墙的空地不一定能到达那个空地。因为这个wa了好久,其他的相邻的空地之间是双向边。

主要是要想到将网格之间的可行路建边。

#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
struct node
{
int to,nxt,w;
}h[];
int n,m,a[][],ex,ey,sx,sy,tot,nxt[],d[][],lq[][],rq[][],uq[][],dq[][];
int dis[];
char ch[];
queue< pair<int,int> > q;
bool vis[][],v[];
void add(int x,int y,int w)
{
h[++tot].to=y;
h[tot].nxt=nxt[x];
h[tot].w=w;
nxt[x]=tot;
}
int getpos(int x,int y)
{
return (x-)*m+y;
}
void ad(int x,int y,int ds)
{
if(a[x][y]){
if(ds<=d[x][y]){
d[x][y]=ds;
if(!vis[x][y]){
q.push(make_pair(x,y));
vis[x][y]=;
}
}
}
}
void bfs()
{
while(q.size()){
int x=q.front().first,y=q.front().second;
q.pop();vis[x][y]=;
ad(x-,y,d[x][y]+);
ad(x+,y,d[x][y]+);
ad(x,y-,d[x][y]+);
ad(x,y+,d[x][y]+);
}
}
void init()
{
for(int i=n;i>=;i--){
for(int j=m;j>=;j--){
if(a[i][j]){
if(!a[i+][j]) dq[i][j]=getpos(i,j);
else dq[i][j]=dq[i+][j];
if(!a[i][j+]) rq[i][j]=getpos(i,j);
else rq[i][j]=rq[i][j+];
}
}
}
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(a[i][j]){
if(!a[i-][j]) uq[i][j]=getpos(i,j);
else uq[i][j]=uq[i-][j];
if(!a[i][j-]) lq[i][j]=getpos(i,j);
else lq[i][j]=lq[i][j-];
}
}
}
}
void build()
{
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(a[i][j]){
if(a[i-][j]) add(getpos(i,j),getpos(i-,j),);
if(a[i+][j]) add(getpos(i,j),getpos(i+,j),);
if(a[i][j-]) add(getpos(i,j),getpos(i,j-),);
if(a[i][j+]) add(getpos(i,j),getpos(i,j+),);
if(lq[i][j]!=getpos(i,j)) add(getpos(i,j),lq[i][j],d[i][j]);
if(rq[i][j]!=getpos(i,j)) add(getpos(i,j),rq[i][j],d[i][j]);
if(uq[i][j]!=getpos(i,j)) add(getpos(i,j),uq[i][j],d[i][j]);
if(dq[i][j]!=getpos(i,j)) add(getpos(i,j),dq[i][j],d[i][j]);
} }
}
}
void spfa()
{
queue<int> qq;
memset(dis,0x3f,sizeof(dis));
qq.push(getpos(sx,sy));
dis[getpos(sx,sy)]=;
v[getpos(sx,sy)]=;
while(qq.size()){
int x=qq.front();qq.pop();v[x]=;
for(int i=nxt[x];i;i=h[i].nxt){
int y=h[i].to;
if(dis[y]>=dis[x]+h[i].w){
dis[y]=dis[x]+h[i].w;
if(!v[y]){
v[y]=;
qq.push(y);
}
}
}
}
}
int main()
{
memset(d,0x3f,sizeof(d));
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%s",ch+);
for(int j=;j<=m;j++){
if(ch[j]=='.') a[i][j]=;
else if(ch[j]=='C') sx=i,sy=j,a[i][j]=;
else if(ch[j]=='F') ex=i,ey=j,a[i][j]=;
else{
q.push(make_pair(i,j));
vis[i][j]=;
d[i][j]=;
}
}
}
bfs();init();build();spfa();
if(dis[getpos(ex,ey)]>=){
puts("no");
return ;
}
printf("%d\n",dis[getpos(ex,ey)]);
return ;
}

走格子

T3 柱状图此题不可做。。。

首先,以一个点为最高点,那么需要变动的高度是一个单谷的函数,所以三分答案。

我们可以O(n)枚举以谁为最高点,O(logn)三分最高点的高度,O(n)计算答案,总复杂度O(n2logn)。可以得到60分的好成绩。

其实这个思路已经很接近正解了。枚举最高点和三分高度无法优化(skyh的三分答案+退火我不做任何评价,因为我不会),那么就只能对计算答案下手了。

我们确定了最高点(x 枚举)和最高高度(h[x] 三分)那么图形的形状就是确定的了。

设i为x左边的一个点,应该的高度为h[i],原始高度为a[i];

h[i]=h[x]-abs(i-x)  去绝对值得 h[i]-i=h[x]-x 他需要改变的高度Δh=abs(h[i]-a[i])=abs( (h[i]-i)-(a[i]-i) )=abs( (h[x]-x)-(a[i]-i) )

再次分类去绝对值 (h[x]-x)>(a[i]-i) Δh=(h[x]-x)-(a[i]-i)

那么我们设满足i<x&&(h[x]-x)>(a[i]-i) 有cnt个,他们对答案的贡献为cnt×(h[x]-x)-Σ(a[i]-i)

cnt和(a[i]-i)可以用两个树状数组维护:将(a[i]-i)和i当做二元组存起来,按a[i]-i的大小进行排序,得到每个点在数组中的位置。用现在的位置当作树状数组的下标,维护(a[i]-i)的和 和cnt的个数。因为我们是从左往右扫,扫完一个点才会把他对应的值加入树状数组,所以当前树状数组中的值都是满足i<x的。那么我们只需要找到(a[i]-i)<=(h[x]-x)的最后一个位置pos。二分找到这个位置(排序后的数组),他对应的下标就是树状数组中下标的位置。

同理(a[i]-i)>(h[x]-x)的情况 Σ(a[i]-i)-cnt×(h[x]-x) 只需要查询到n的,然后减去pos以前的,剩下的就是我们想要的。

在x右边的也一样,h[i]+i=h[x]+x,其他的一样维护。

这题一共4个树状数组。。。。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll n,ans,mm,a[],idl[],idr[];
pair<ll,ll> l[],r[];
struct node
{
ll c[],cc[];
ll lowbit(ll x)
{
return x&(-x);
}
void add(ll x,ll w,ll num){
while(x<=n){
c[x]+=w;
cc[x]+=num;
x+=lowbit(x);
}
}
pair<ll,ll> query(ll x)
{
pair<ll,ll> as;
while(x){
as.first+=c[x];
as.second+=cc[x];
x-=lowbit(x);
}
return as;
}
}L,R;
ll calc(ll x,ll height)
{
ll res=abs(a[x]-height);
ll pos=upper_bound(l+,l+n+,make_pair(height-x,1ll))-l-;
pair<ll,ll> cost=L.query(pos);
res+=cost.second*(height-x)-cost.first;
pair<ll,ll> cst=L.query(n);
cst.first-=cost.first;cst.second-=cost.second;
res+=cst.first-cst.second*(height-x); pos=upper_bound(r+,r+n+,make_pair(height+x,1ll))-r-;
cost=R.query(pos);
res+=cost.second*(height+x)-cost.first;
cst=R.query(n);
cst.first-=cost.first;cst.second-=cost.second;
res+=cst.first-cst.second*(height+x);
return res;
}
void work()
{
for(ll i=;i<=n;i++) R.add(idr[i],r[idr[i]].first,);
for(ll i=;i<=n;i++){
R.add(idr[i],-r[idr[i]].first,-);
ll lb=max(i,n-i+),rb=mm+n;
while(lb+<rb){
ll mid=(lb+rb)>>;
ll lmid=mid-,rmid=mid;
ll lcost=calc(i,lmid),rcost=calc(i,rmid);
if(lcost>=rcost) lb=mid;
else rb=mid;
}
ans=min(ans,calc(i,lb));
ans=min(ans,calc(i,rb));
L.add(idl[i],l[idl[i]].first,);
}
}
int main()
{
scanf("%lld",&n);ans=0x7ffffffffffffff;
for(ll i=;i<=n;i++){
scanf("%lld",&a[i]);
mm=max(mm,a[i]);
l[i]=make_pair(a[i]-i,i);
r[i]=make_pair(a[i]+i,i);
}
sort(l+,l+n+);
sort(r+,r+n+);
for(ll i=;i<=n;i++){
idl[l[i].second]=i;
idr[r[i].second]=i;
}
work();
printf("%lld\n",ans);
return ;
}

柱状图

改了一下午。。。树状数组的下标理解错了,怎么都不知道是怎么维护的。

8.7 NOIP模拟测试14 旋转子段+走格子+ 柱状图的更多相关文章

  1. NOIP模拟测试14「旋转子段·走格子·柱状图」

    旋转子段 连60分都没想,考试一直肝t3,t2,没想到t1最简单 我一直以为t1很难,看了题解发现也就那样 题解 性质1 一个包含a[i]旋转区间值域范围最多为min(a[i],i)----max(a ...

  2. NOIP模拟测试14

    考完19了再写14,我也是够咕的. 14的题很好,也充分暴露了我的问题. T1是个分析性质推结论的题 对于区间[L,R],不妨设a[L]!=a[R],那么两个端点对答案没有贡献,也就是[L+1,R], ...

  3. 2019.8.7 NOIP模拟测试14 反思总结

    先扔代码 调完自闭网络流了,新一轮考试前看看能不能赶完…… 考得极其爆炸,心态也极其爆炸,真的是认识到自己能力上的不足 思维跑偏,代码能力差 就这样吧,再努力努力,不行就AFO T1旋转子段: 因为我 ...

  4. 「题解」NOIP模拟测试题解乱写II(36)

    毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...

  5. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  6. 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

    2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...

  7. 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)

    2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...

  8. NOIP模拟测试17&18

    NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...

  9. 2019.8.14 NOIP模拟测试21 反思总结

    模拟测试20的还没改完先咕着 各种细节问题=错失190pts T1大约三分钟搞出了式子,迅速码完,T2写了一半的时候怕最后被卡评测滚去交了,然后右端点没有初始化为n…但是这样还有80pts,而我后来还 ...

随机推荐

  1. pytorch——auto-encoders

    自动编码器的训练方法: (1)Loss function for binary inputs (2)Loss function for real-valued inputs

  2. ICT638 Mobile and App Development

    Assessment Cover SheetStudent ID CohortStudent NameProgrammeEnrolledDiploma in Information Technolog ...

  3. 解决 IDEA 无法找到 java.util.Date 的问题

    原文首发于 studyidea.cn点击查看更多技巧 问题 最近在项目中频繁使用到 java.util.Date,但是使用 IDEA 提示查找 Date 类,却无法找到 java.util.Date. ...

  4. WPF ToggleButton Style

    <Style x:Key="ArrowToggleStyle" TargetType="ToggleButton"> <Setter Prop ...

  5. 『CSP2019初赛后的总结』

    初赛已经过去了,分数大概也已经知道了,接下来的一个月停课应该就是全部准备复赛. 联赛前几次讲课的内容是组合计数,计数\(dp\),字符串,概率期望,数论,数据结构,多数知识点难度都是大于联赛难度的,不 ...

  6. JavaScript定时器越走越快的问题

    目录 JavaScript定时器越走越快的问题 (setinterval)多次初始化 清除(clearInterval)的失效 解决方法 JavaScript定时器越走越快的问题 之前在项目中写了定时 ...

  7. .net Dapper 学习系列(1) ---Dapper入门

    目录 写在前面 为什么选择Dapper 在项目中安装Dapper 在项目中使用Dapper 在项目中使用Dapper 进行单表增删改数据操作 总结 写在前面 Dapper 是一款轻量级ORM架构.为解 ...

  8. easyui 扩展 datagrid 数据网格视图

    效果如图: js代码: $("#tdg").datagrid({            width: 200,            url: "/Laboratory/ ...

  9. Python - 迭代器与生成器 - 第十三天

    Python 迭代器与生成器 迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问 ...

  10. 小鸟初学Shell编程(九)环境变量变量配置文件

    介绍 在上一篇使用完了环境变量,并且知道PATH环境变量概念,那么我们对命令的执行就有了一定深入的理解.那么PATH环境变量或其他环境变量是保存在哪呢?那么这篇文章主要介绍环境变量配置文件. 配置文件 ...