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,而我后来还 ...
随机推荐
- 【JavaScript】使用纯JS实现多张图片的懒加载(附源码)
一.效果图如下 上面的效果图,效果需求如下 1.还没加载图片的时候,默认显示加载图片背景图 2.刚开始进入页面,自动加载第一屏幕的图片 3.下拉界面,当一张图片容器完全显露出屏幕,即刻加载图片,替换背 ...
- 死磕 java线程系列之线程池深入解析——体系结构
(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 简介 Java的线程池是块硬骨头,对线程池的源码做深入研究不仅能提高对Java整个并发编程的理解,也能提高自己 ...
- liunx下安装MySQL
1.安装依赖包:yum -y install gcc gcc-c++ ncurses ncurses-devel cmake bisonyum install -y perl-Module-Insta ...
- Mysql存储引擎以及锁机制
一.常用命令 1.查看引擎(默认为InnoDB) 查看mysql提供的存储引擎:show engienes 查看mysql当前默认的存储引擎:show variables like '%storage ...
- SQL server数据库系统部分常用的存储过程及说明
--SQL server数据库系统常用的存储过程 exec sp_databases --能看到所有具有权限的数据库名,大小和备注 exec sp_helpdb --数据库名,大小,管理员,创建时间状 ...
- bs4 UnicodeEncodeError: 'gbk' codec can't encode character '\xa0'
Problem: 写爬虫时,出现了以下错误: 意思是Unicode编码错误,gbk编解码器不能编码\xa0字符. 爬取信息包含中文,使用BeautifulSoup库解析网页,用get_text()方法 ...
- Linux防火墙常用操作
/tcp —— 配置白名单 sudo systemctl start firewalld — 启动防火墙 sudo firewall-cmd --state - 看状态 sudo firewall-c ...
- RAID 10 配置流程
1.在虚拟机中再添加5块硬盘: 2.fdisk -l 可以查看当前虚拟机中的磁盘情况. 3.使用mdadm命令创建RAID10,名称为”/dev/md0″. -C代表创建操作,-v显示创建过程,-a ...
- web安全之XSS基础-常见编码科普
0x01常用编码 html实体编码(10进制与16进制): 如把尖括号编码[ < ] -----> html十进制: < html十六进制:< javascript的八进制 ...
- 数据挖掘:关联规则的apriori算法在weka的源码分析
相对于机器学习,关联规则的apriori算法更偏向于数据挖掘. 1) 测试文档中调用weka的关联规则apriori算法,如下 try { File file = new File("F:\ ...