NOIP模拟测试14
考完19了再写14,我也是够咕的。
14的题很好,也充分暴露了我的问题。
T1是个分析性质推结论的题
对于区间[L,R],不妨设a[L]!=a[R],那么两个端点对答案没有贡献,也就是[L+1,R],[L,R-1]都是符合题意的区间。
即 最优的区间的两个端点一定相等
然后把每个数的位置和大小作为区间的两端点,统计答案即可。
#include<bits/stdc++.h>
#define F(n) for(int i=1;i<=n;i++)
int a[],sum[],n,ans;
std::vector< std::pair<int,int> >k[<<];
int main(){
scanf("%d",&n);
F(n)scanf("%d",&a[i]),sum[i]=sum[i-]+(a[i]==i);ans=sum[n];
F(n)k[a[i]+i].push_back(std::make_pair(std::min(i,a[i]),std::max(i,a[i])));
F((n<<))sort(k[i].begin(),k[i].end());
F((n<<))
for(int t=k[i].size(),j=t-,last=;j>=;j--,last++)
ans=std::max(ans,last++sum[k[i][j].first-]+sum[n]-sum[k[i][j].second]);
std::cout<<ans;
}
T2走格子
关键在于如何将题目抽象成图论模型,而不是只一味的搜索。
这道题没有太多的限制,只有移动到每个格子的距离的不同。
因此直接建边,跑dijstra即可
#include<bits/stdc++.h>
#define MAXN 505
using namespace std;
const int h[]={,,-,,},l[]={,,,,-};
int mp[MAXN][MAXN],endx,endy,n,m,tot=;
priority_queue<pair<int,int> >Q;
vector<int>zh[MAXN],zl[MAXN];
bool vst[MAXN*MAXN];
int ans=0x7f7f7f7f,stax,stay;
int p[MAXN][MAXN],d[MAXN*MAXN],nxt[MAXN*MAXN*],val[MAXN*MAXN*],to[MAXN*MAXN*],cnt,head[MAXN*MAXN];
void add(int u,int v,int w)
{
to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;val[cnt]=w;
return ;
}
int dijstra()
{
memset(d,0x3f,sizeof(d));d[p[stax][stay]]=;
Q.push(make_pair(,p[stax][stay]));
while(Q.size())
{
int k=Q.top().second;Q.pop();
if(k==p[endx][endy])return d[k];
if(vst[k])continue;
vst[k]=;
for(int i=head[k];i;i=nxt[i])
{
int y=to[i];
if(d[y]>d[k]+val[i])
{
d[y]=d[k]+val[i];
Q.push(make_pair(-d[y],y));
}
}
}
return 0x7f7f7f7f;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
p[i][j]=++tot;
char c=getchar();
while(c!='C'&&c!='F'&&c!='.'&&c!='#')c=getchar();
if(c=='C')stax=i,stay=j,mp[i][j]=;
else if(c=='F')endx=i,endy=j,mp[i][j]=;
else if(c=='.')mp[i][j]=;
else mp[i][j]=;
}
}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(!mp[i][j])zh[i].push_back(j);
for(int j=;j<=m;j++)
for(int i=;i<=n;i++)
if(!mp[i][j])zl[j].push_back(i);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
if(!mp[i][j])continue;
if(i^&&mp[i-][j])add(p[i][j],p[i-][j],);
if(i^n&&mp[i+][j])add(p[i][j],p[i+][j],);
if(j^&&mp[i][j-])add(p[i][j],p[i][j-],);
if(j^m&&mp[i][j+])add(p[i][j],p[i][j+],);
int up=*(--lower_bound(zl[j].begin(),zl[j].end(),i));
int down=*(lower_bound(zl[j].begin(),zl[j].end(),i));
int lef=*(--lower_bound(zh[i].begin(),zh[i].end(),j));
int rig=*(lower_bound(zh[i].begin(),zh[i].end(),j));
int dis=min(i-up,min(down-i,min(j-lef,rig-j)));
add(p[i][j],p[up+][j],dis);
add(p[i][j],p[down-][j],dis);
add(p[i][j],p[i][lef+],dis);
add(p[i][j],p[i][rig-],dis);
}
ans=dijstra();
if(ans==0x7f7f7f7f)cout<<"no"<<endl;
else cout<<ans<<endl;
return ;
}
T3柱状图 好题标记
这道题考察的是三分。
观察一下可知对于某一位置来说,其高度大小与最终答案的关系是单谷的。
(当你得到一个最优答案的时候,如果变大会使其余的柱子在原基础上再上升一个,反之亦然)
于是60分做法诞生:
枚举位置,三分高度,统计答案 O(n^2logn)
#include<bits/stdc++.h>
#define MAXN 100005
#define int long long
#define F(x) for(int i=1;i<=n;i++)
#define re register
#define min(a,b) (a)<(b)?(a):(b)
using namespace std;
int a[MAXN],now,n,maxn;
inline int Get(int h)
{
int ans=abs(h-a[now]);
F(n)
{
if(i==now)continue;
if(h-abs(i-now)<=)return 0x7f7f7f7f7f7f7ff;
ans+=abs(a[i]-(h-abs(i-now)));
}
return ans;
}
inline int San_fen()
{
int l=now,r=maxn*;
while(l+<r)
{
int lmid=l+(r-l)/;
int rmid=r-(r-l)/;
if(Get(lmid)<Get(rmid))r=rmid;
else l=lmid;
}
return min(Get(l),min(Get(l+),Get(l+)));
}
signed main()
{
re int ans=0x7f7f7f7f7f7f7ff;
scanf("%lld",&n);
F(n)scanf("%lld",&a[i]),maxn=max(maxn,a[i]);
for(now=;now<=n;now++)
ans=min(ans,San_fen());
cout<<ans<<endl;
return ;
}
考虑优化,对于统计答案,我们分情况讨论一下
(讨论个毛线)详情见这里
主要说一下skyh的垃圾退火(雾)
模拟退火是一个特别神(kan)奇(lian)的算法。
是这样的:
根据物理学常识我们可以知道,物体内能越小越稳定。
所谓的模拟退火,就是模拟这个过程。
1.设置初始温度T0
2.找出下一个目标位置
3.尝试用新的答案更新旧的答案
4.降温
是不是一脸蒙蔽?
详细来说:
while(T>eps) //终止边界
{
tmp=now+(rand()*2ll-RAND_MAX)*T*0.000001; //温度越高,变化越大
if(T<1.0)tmp=max(tmp,1ll),tmp=min(tmp,n); //当温度小于一定程度的时候,让下一个位置尽量小地变化
else tmp=(tmp%n+n)%n+; //让下一个位置在要求的范围内
tmpans=calc(tmp);D=-fabs(tmpans-nowans); //找到新的解
if(tmpans<nowans||exp(D/T)*RAND_MAX>rand())nowans=tmpans,now=tmp; //根据概率确定答案是否改变
if(tmpans<ans)ans=tmpans; //更新最终的答案
T*=0.975; //降温
}
根据前人的经验,这个更新的概率是exp(D/T)(D是变化量绝对值的相反数,T是当前温度)
最后附上完整代码
#include<bits/stdc++.h>
#define MAXN 100005
#define int long long
using namespace std;
int yx[MAXN],n,now;
struct Bit{
int tr[][MAXN];
void insert(int x,int val,int opt)
{
for(int i=x;i<=n;i+=i&-i)tr[][i]+=val,tr[][i]+=opt;
return ;
}
pair<int,int> query(int x)
{
int num=,ans=;
for(int i=x;i;i-=i&-i)num+=tr[][i],ans+=tr[][i];
return make_pair(ans,num);
}
}T[];
int sa[MAXN],sb[MAXN],ap[MAXN],bp[MAXN],ans=0x7f7f7f7f7f7f7ff,maxa,a[MAXN],b[MAXN];
inline int check(int x)
{
if(x<now||x<(n-now+))return 0x7f7f7f7f7f7f7ff;
int ans=abs(x-yx[now]);
int num=upper_bound(a+,a+n+,x-now)-a-;
pair<int,int> w=T[].query(num);
ans+=abs(w.first-w.second*(x-now))+abs(sa[now-]-w.first-(now--w.second)*(x-now));
num=upper_bound(b+,b+n+,x+now)-b-;
w=T[].query(num);
ans+=abs(w.first-(now+x)*w.second)+abs(sb[n]-sb[now]-w.first-(n-now-w.second)*(now+x));
return ans;
}
inline int san_fen()
{
int l=,r=maxa*;
while(l+<r)
{
int lmid=l+(r-l)/,
rmid=r-(r-l)/;
if(check(lmid)<check(rmid))r=rmid;
else l=lmid;
}
return min(check(l+),min(check(l+),check(l)));
}
signed main()
{
cin>>n;
for(int i=;i<=n;i++)
{
scanf("%lld",&yx[i]);
ap[i]=a[i]=yx[i]-i;
bp[i]=b[i]=yx[i]+i;
sa[i]=sa[i-]+a[i];
sb[i]=sb[i-]+b[i];
maxa=max(maxa,yx[i]);
}
sort(a+,a+n+);sort(b+,b+n+);
for(int i=;i<=n;i++)
{
ap[i]=lower_bound(a+,a+n+,ap[i])-a;
bp[i]=lower_bound(b+,b+n+,bp[i])-b;
}
for(int i=;i<=n;i++)T[].insert(bp[i],yx[i]+i,);
for(now=;now<=n;now++)
{
T[].insert(bp[now],-(yx[now]+now),-);
ans=min(san_fen(),ans);
T[].insert(ap[now],yx[now]-now,);
}
cout<<ans<<endl;
return ;
}
正解AC
#include<bits/stdc++.h>
#define MAXN 100005
#define int long long
#define re register
using namespace std;
double eps=1e-,T=,D;
int mid,n,a[MAXN],b[MAXN];
inline int calc(int x)
{
for(int i=;i<=n;i++)b[i]=a[i]+abs(i-x);
nth_element(b+,b+mid,b+n+);
re int now=max(b[mid],max(x,n-x+)),ans=;
for(int i=;i<=n;i++)
{
if(now-abs(i-x)<=)return 0x7f7f7f7f7f;
ans+=abs(now-b[i]);
}
return ans;
}
signed main()
{
srand((unsigned)time());
cin>>n;
mid=(+n)>>;
for(int i=;i<=n;i++)scanf("%lld",&a[i]);
int ans=0x7f7f7f7f7f7f;
int now=(+n>>);
int nowans=calc(now),tmp,tmpans;
while(T>eps)
{
tmp=now+(rand()*2ll-RAND_MAX)*T*0.000001;
if(T<1.0)tmp=max(tmp,1ll),tmp=min(tmp,n);
else tmp=(tmp%n+n)%n+;
tmpans=calc(tmp);D=-fabs(tmpans-nowans);
if(tmpans<nowans||exp(D/T)*RAND_MAX>rand())nowans=tmpans,now=tmp;
if(tmpans<ans)ans=tmpans;
T*=0.975;
}
cout<<ans<<endl;
return ;
}
退火AC
模拟退火是一个特别优秀的算法,请不要针对算法,(尽管你可以针对脸某)。
NOIP模拟测试14的更多相关文章
- 8.7 NOIP模拟测试14 旋转子段+走格子+ 柱状图
T1 旋转子段 30% 暴力枚举起点和长度,暴力判断,o(n3) 不知道为什么我拿了40分... 60% 每一个点都有一个固定的旋转中心可以转成固定点,枚举旋转点和长度. 100% 用一个vecto ...
- 2019.8.7 NOIP模拟测试14 反思总结
先扔代码 调完自闭网络流了,新一轮考试前看看能不能赶完…… 考得极其爆炸,心态也极其爆炸,真的是认识到自己能力上的不足 思维跑偏,代码能力差 就这样吧,再努力努力,不行就AFO T1旋转子段: 因为我 ...
- NOIP模拟测试14「旋转子段·走格子·柱状图」
旋转子段 连60分都没想,考试一直肝t3,t2,没想到t1最简单 我一直以为t1很难,看了题解发现也就那样 题解 性质1 一个包含a[i]旋转区间值域范围最多为min(a[i],i)----max(a ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色
2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)
2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...
- NOIP模拟测试17&18
NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...
- 2019.8.14 NOIP模拟测试21 反思总结
模拟测试20的还没改完先咕着 各种细节问题=错失190pts T1大约三分钟搞出了式子,迅速码完,T2写了一半的时候怕最后被卡评测滚去交了,然后右端点没有初始化为n…但是这样还有80pts,而我后来还 ...
随机推荐
- Spring Cloud Config Server 节点迁移引起的问题,请格外注意这一点!
前言: 虽然强烈推荐选择使用国内开源的配置中心,如携程开源的 Apollo 配置中心.阿里开源的 Nacos 注册&配置中心. 但实际架构选型时,根据实际项目规模.业务复杂性等因素,有的项目还 ...
- webpack loader实现
正值前端组件化开发时代,那么必然离不开目前最火的构建工具--webpack(grunt,gulp等暂且不谈).说到这里,刚好有几个问题: 为什么运行打包命令之后,.vue 文件可以转成 .js 文件 ...
- Http协议Content-Length详解
前言 http协议是互联网中最重要的协议之一,虽然看上去很简单,但是实际中经常遇到问题,我们就已经遇到好几次了.有长连接相关的,有报文解析相关的.对http协议不能一知半解,必须透彻理解才行.本文通过 ...
- 导图梳理springboot手动、自动装配,让springboot不再难懂
什么是springboot 在学springboot之前,你必须有spring.spring mvc基础,springboot的诞生其实就是用来简化新Spring应用的初始搭建以及开发过程,该框架使用 ...
- dubbo配置文件的加载顺序详解(图示)
Dubbo配置文件的加载顺序 在使用apache dubbo.version2.7.3 时,配置文件的加载情况.以provider提供服务者为例. 配置文件 ,以下四个配置文件. 其优先级 app ...
- Linux之常用命令I
一.Linux简介 1)Minix(只为教学,开源的)-->Linux(以前者为模板,添加了一些软件) 2)Linux分为内核版本和发行版本 区别:Linux内核版本就是核心版本,不用最新版本, ...
- C++简单程序设计
计算机的最基本功能是数据处理 l C++支持的基本数据类型: n 整数.实数.字符.布尔数据 l C++支持的基本运算 n 算术运算.关系运算.逻辑运算.位运算.逗号运算.条件运算 程序要能够 ...
- 【Java 基础】谈谈集合.List
目录 1. ArrayList 1.1 ArrayList的构造 1.2 add方法 1.3 remove方法 1.4 查询方法 1.5 一些其他常用方法 1.6 ArrayList小结 2. Vec ...
- Codeforces Round #426 The Meaningless Game
题目网址:http://codeforces.com/contest/834/problem/C 题目: C. The Meaningless Game Slastyona and her loyal ...
- css的简单使用
css语法 id选择器: id 选择器可以为标有特定 id 的 HTML 元素指定特定的样式. HTML元素以id属性来设置id选择器,CSS 中 id 选择器以 "#" 来定义. ...