NOIP2017赛前模拟11月4日总结:
第一次挂0·····有点感伤···主要是因为时间分配太不合理了··花2个半小时搞第一题最后还wa完了··第二题很简单花了30分钟打完但没打对拍结果wa完···第三题暴力可以拿20分的但没时间打了···
第一次感受到了暴力的重要性··第一是想不出正解部分分是要拿的··第二是即使想出正解对拍也要用暴力···
以后考试决定遇到一道题先只想个20分钟·如果想不出正解先把暴力打了··三道题这样弄完后再去细细想正解
题目1:区间
给定一个n个正整数的序列··q次询问两个数a,b,问序列中有多少个区间使得ab出现次数相等(0次也算),n<=8000,q<=500000
先说暴力的方法··我们统计完前缀和后找出满足题意的区间lr为sum[a][r]-sum[a][l-1]=sum[b][r]-sum[b][l-1],移项后为sum[a][r]-sum[b][r]=sum[a][l-1]-sum[b][l-1],因此对于每次询问直接开一个桶记录每个两个数每一个位置的sum[a][i]-sum[b][i]的值的总数计算即可···顺便讨论一下ab是否存在于序列中的情况,注意ab有可能相等
其实正解只是暴力的优化····这道题明显也想不出什么巧妙的方法··第一点是我们可以发现我们计算sum[a][i]-sum[b][i]的效果等效于我们在遍历每个位置时记录一个tag,遇到a的话+1,遇到b的话-1,每个位置上的tag值实际上就是sum[a][i]-sum[b][i],因此不用统计前缀和直接扫就可以了··第二点是我们可以发现暴力是对于每次询问我们是暴力O(n)扫过去的··其实可以发现中途的不是ab的位置实际上是多余的···因此我们完全可以开个数组记录每个数出现的位置(推荐用vector动态开··很方便··考试时脑子抽了写了个手动数组麻烦死··)对于询问的两个数将两个数的位置数组按序合并然后直接在位置数组上扫就可以了·····可以证明优化后的复杂度是n^2的
代码:
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int N=;
const int M=5e5+;
inline int R(){
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f;
}
struct node{int x,y;}q[M];
vector<int>pos[N];
int tub[N*],n,Q,b[N],cnt,num[N],tim,visit[N*];
inline void lsh(){
sort(b+,b+cnt+);
cnt=unique(b+,b+cnt+)-b-;
for(int i=;i<=n;i++) num[i]=lower_bound(b+,b+cnt+,num[i])-b;
}
int main(){
n=R(),Q=R();
for(int i=;i<=n;i++) num[i]=R(),b[++cnt]=num[i];
lsh();
for(int i=;i<=Q;i++){
q[i].x=R(),q[i].y=R();
int tx=lower_bound(b+,b+cnt+,q[i].x)-b;
int ty=lower_bound(b+,b+cnt+,q[i].y)-b;
if(b[tx]!=q[i].x) q[i].x=;
else q[i].x=tx;
if(b[ty]!=q[i].y) q[i].y=;
else q[i].y=ty;
}
for(int i=;i<=n;i++) pos[num[i]].push_back(i);
for(register int i=;i<=Q;i++){
if((!q[i].x&&!q[i].y)||q[i].x==q[i].y){cout<<(n+)*n/<<endl;continue;}
static int loc[N];int temp=,a=q[i].x,b=q[i].y;
register int head1=,head2=;
while(head1<pos[a].size()||head2<pos[b].size()){
if(head1==pos[a].size()){
while(head2<pos[b].size()) loc[++temp]=pos[b][head2],head2++;
continue;
}
if(head2==pos[b].size()){
while(head1<pos[a].size()) loc[++temp]=pos[a][head1],head1++;
continue;
}
if(pos[a][head1]>pos[b][head2]) loc[++temp]=pos[b][head2],head2++;
else loc[++temp]=pos[a][head1],head1++;
}
if(!a||!b){
long long ans=;
for(int i=;i<=temp;i++) ans+=(loc[i]-loc[i-]-)*(loc[i]-loc[i-])/;
ans+=(n-loc[temp])*(n-loc[temp]+)/;
cout<<ans<<endl;
}
else{
tim++;int maxx,minn,tag=N;
tub[N]=;visit[N]=tim;maxx=minn=N;long long ans=;
for(register int i=;i<=temp;i++){
if(num[loc[i]]==a){
tag++;maxx=max(maxx,tag),minn=min(minn,tag);
if(visit[tag]!=tim) tub[tag]=,visit[tag]=tim;
else tub[tag]++;
}
else{
tag--;maxx=max(maxx,tag),minn=min(minn,tag);
if(visit[tag]!=tim) tub[tag]=,visit[tag]=tim;
else tub[tag]++;
}
if(i!=temp) tub[tag]+=loc[i+]-loc[i]-;
else tub[tag]+=n-loc[i];
}
tub[N]+=loc[]-;
for(register int i=minn;i<=maxx;i++)
if(visit[i]==tim) ans+=tub[i]*(tub[i]-)/;
cout<<ans<<endl;
}
}
return ;
}
题目2:排列
给定n个数的排列的每个位置上的数的逆序数的前缀和(逆序数:前面的数中比该数大的数的个数),求出该排列····
很简单的一道题··我们先将通过前缀和直接算出每个数的逆序数(从后往前一次用这个位置的前缀和减去下一个位置的前缀和考试的时候我是从前往后减的坑爹样例没有看出错),这时我们从后往前以此处理···很明显对于每个位置的逆序数a,我们知道它前面的数中有多少个数比它大从而知道了它的排名··直接用线段树区间查询k大值就可以了,再将它删除
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
inline long long R(){
char c;long long f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=f*+c-'';
return f;
}
const int N=1e5+;
int tree[N*],n,anss[N],temp;
long long num[N];
inline void build(int k,int l,int r){
if(l==r){
tree[k]++;return;
}
int mid=(l+r)/;
build(k*,l,mid);build(k*+,mid+,r);
tree[k]=tree[k*]+tree[k*+];
}
inline void find(int k,int l,int r,int x){
if(l==r){
tree[k]--;temp=l;return;
}
int mid=(l+r)/;
if(x<=tree[k*]) find(k*,l,mid,x);
else find(k*+,mid+,r,x-tree[k*]);
tree[k]=tree[k*]+tree[k*+];
}
int main(){
//freopen("premu.in","r",stdin);
//freopen("premu.out","w",stdout);
n=R();
for(int i=;i<=n;i++) num[i]=R();
for(int i=n;i>=;i--) num[i]-=num[i-];
build(,,n);
for(int i=n;i>=;i--){
find(,,n,i-num[i]);
anss[i]=temp;
}
for(int i=;i<=n;i++) cout<<anss[i]<<" ";
return ;
}
题目3:边的处理
有一个n个点的无向图,给出m条边,每条边的信息形如x,y,c,r
给出q组询问形如u,v,l,r
接下来解释询问以及边的意义。
询问表示,一开始你在点u上,然后按顺序处理编号从l到r的边。
对于一条边xycr,你可以进行两次操作:
1、如果你当前在x点或者y点上,那么你可以走这条边(从x到y或从y到x)并付出c的代价(当然你也可以不走,看操作2)。
2、如果你不走这条边或者不可以走这条边(即你当前不在x或y上),那么你需要付出r的代价。
询问如果要从点u开始,按顺序处理完编号从l到r的边之后到达点v的最小代价,如果不能到达u,那么输出-1
n<=30,m<=20000,q<=200000
很好的分治题···
暴力的话我们考虑对于每次询问的话每次处理到某一条边时所在点的所有的情况然后想最短路一样更新它到起点的距离
分治的话挺复杂的,具体见http://blog.csdn.net/qq_35649707/article/details/78439108,%%%%%%%%%
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=2e4+;
const int N=2e5+;
const int inf=0x3f3f3f3f;
inline int R(){
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f;
}
struct node{
int x,y,c,r,u,v,l,id;
}ed[M],q[N];
int n,m,Q,f[M][][],anss[N];
inline void solve(int l,int r,int x,int y){
if(x>y) return;
if(l==r){
if(ed[l].x>ed[l].y) swap(ed[l].x,ed[l].y);
for(int i=x;i<=y;i++){
if(q[i].u>q[i].v) swap(q[i].u,q[i].v);
if(q[i].l==l&&q[i].u==ed[l].x&&q[i].v==ed[l].y) anss[q[i].id]=ed[l].c;
if(q[i].u==q[i].v) anss[q[i].id]=min(anss[q[i].id],ed[l].r);
}
return;
}
static node d[N];int ri=y+,le=x-,mid=(l+r)/;
memset(f[mid],inf,sizeof(f[mid]));
f[mid][ed[mid].x][ed[mid].y]=f[mid][ed[mid].y][ed[mid].x]=ed[mid].c;
for(int i=;i<=n;i++) f[mid][i][i]=min(f[mid][i][i],ed[mid].r);
for(int i=mid-;i>=l;i--){
for(int j=;j<=n;j++)
for(int k=;k<=n;k++)
f[i][j][k]=f[i+][j][k]+ed[i].r;
for(int j=;j<=n;j++) f[i][ed[i].x][j]=min(f[i][ed[i].x][j],f[i+][ed[i].y][j]+ed[i].c);
for(int j=;j<=n;j++) f[i][ed[i].y][j]=min(f[i][ed[i].y][j],f[i+][ed[i].x][j]+ed[i].c);
}
memset(f[mid+],inf,sizeof(f[mid+]));
f[mid+][ed[mid+].x][ed[mid+].y]=f[mid+][ed[mid+].y][ed[mid+].x]=ed[mid+].c;
for(int i=;i<=n;i++) f[mid+][i][i]=min(f[mid+][i][i],ed[mid+].r);
for(int i=mid+;i<=r;i++){
for(int j=;j<=n;j++)
for(int k=;k<=n;k++)
f[i][j][k]=f[i-][j][k]+ed[i].r;
for(int j=;j<=n;j++) f[i][j][ed[i].x]=min(f[i][j][ed[i].x],f[i-][j][ed[i].y]+ed[i].c);
for(int j=;j<=n;j++) f[i][j][ed[i].y]=min(f[i][j][ed[i].y],f[i-][j][ed[i].x]+ed[i].c);
}
for(int i=x;i<=y;i++){
if(q[i].l<=mid&&q[i].r>mid){
anss[q[i].id]=inf;
for(int j=;j<=n;j++) anss[q[i].id]=min(f[q[i].l][q[i].u][j]+f[q[i].r][j][q[i].v],anss[q[i].id]);
}
else if(q[i].r<=mid) d[++le]=q[i];
else d[--ri]=q[i];
}
for(int i=x;i<=le;i++) q[i]=d[i];
for(int i=ri;i<=y;i++) q[i]=d[i];
solve(l,mid,x,le);solve(mid+,r,ri,y);
}
int main(){
//freopen("a.in","r",stdin);
n=R(),m=R(),Q=R();memset(anss,inf,sizeof(anss));
for(int i=;i<=m;i++) ed[i].x=R(),ed[i].y=R(),ed[i].c=R(),ed[i].r=R();
for(int i=;i<=Q;i++) q[i].u=R(),q[i].v=R(),q[i].l=R(),q[i].r=R(),q[i].id=i;
solve(,m,,Q);
for(int i=;i<=Q;i++){
if(anss[i]==inf||anss[i]<) cout<<"-1"<<endl;
else cout<<anss[i]<<endl;
}
return ;
}
NOIP2017赛前模拟11月4日总结:的更多相关文章
- NOIP2017赛前模拟11月6日—7日总结
收获颇丰的两天··· 题目1:序列操作 给定n个非负整数,进行m次操作,每次操作给出c,要求找出c个正整数数并将它们减去1,问最多能进行多少操作?n,m<=1000000 首先暴力贪心肯定是每次 ...
- NOIP2017赛前模拟11月2日总结
分数爆炸的一天··但也学了很多 题目1:活动安排 给定n个活动的开始时间与结束时间··只有一个场地··要求保留尽量多的活动且时间不冲突···场地数n<=100000 考点:贪心 直接将结束时间按 ...
- NOIP2017赛前模拟10月30日总结
题目1: n个人参赛(n<=100000),每个人有一个权值··已知两个人权值绝对值之差小于等于K时,两个人都有可能赢,若大于则权值大的人赢···比赛为淘汰制,进行n-1轮·问最后可能赢的人有多 ...
- 11月30日《奥威Power-BI智能分析报表制作方法》腾讯课堂开课啦
这么快一周就过去了,奥威公开课又要与大家见面咯,上节课老师教的三种报表集成方法你们都掌握了吗?大家都知道,学习的结果在于实际应用,想要熟练掌握新内容的要点就在于去应用它.正是基于这一要点,每一期的课程 ...
- 11月23日《奥威Power-BI报表集成到其他系统》腾讯课堂开课啦
听说明天全国各地区都要冷到爆了,要是天气冷到可以放假就好了.想象一下大冷天的一定要在被窝里度过才对嘛,索性明天晚上来个相约吧,相约在被窝里看奥威Power-BI公开课如何? 上周奥威公开 ...
- 11月16日《奥威Power-BI基于SQL的存储过程及自定义SQL脚本制作报表》腾讯课堂开课啦
上周的课程<奥威Power-BI vs微软Power BI>带同学们全面认识了两个Power-BI的使用情况,同学们已经迫不及待想知道这周的学习内容了吧!这周的课程关键词—— ...
- 11月09日《奥威Power-BI vs微软Power BI》腾讯课堂开课啦
上过奥威公开课的同学可能有一个疑问:奥威Power-BI和微软Power BI是同一个吗,为什么叫同样的名字?正如这个世界上有很多个John.Jack.Marry…一样,奥威Power-BI和微软Po ...
- 2016年11月30日 星期三 --出埃及记 Exodus 20:21
2016年11月30日 星期三 --出埃及记 Exodus 20:21 The people remained at a distance, while Moses approached the th ...
- 2016年11月29日 星期二 --出埃及记 Exodus 20:20
2016年11月29日 星期二 --出埃及记 Exodus 20:20 Moses said to the people, "Do not be afraid. God has come t ...
随机推荐
- jstree 全部选中事件 select_all 使用
select_all function of jstree not checked node for jstree-open branch of ajax-jstree 很尴尬啊,找了整个百度,360 ...
- GUI测试问题汇总
1.ajax实现的页面元素定位问题 最近在做项目的时候遇到一个问题,通过xpath定位到元素后做一个循环操作,第一循环可以正常执行,第二次循环后就报错,错误信息:Message: The elemen ...
- javascript中string对象方法中的slice、substring、substr的区别联系
1.slice.substring.snustr均属于String的对象方法,用于截取或提取字符串片段,三者均布破坏原先的字符串,而是以新的字符串返回被提取的部分. <script> va ...
- JavaScript - 库 jQuery
测试 JavaScript 框架库 - jQuery 引用JQuery 如需测试JavaScript库,您需要在网页中引用它. 为了引用某个库,请使用<script>标签,其src属性设置 ...
- php图片上传旋转压缩方法
用到php的exif扩展,需要开启exif 在php.ini文件中去掉exif组件的注释 extension=php_mbstring.dll //要放在php_exif.dll前面让它先加载 ext ...
- 关于sql server 2008 r2 展开时报错:参数名:viewInfo ( Microsoft SqlServer Management SqlStudio Explorer )解决思路
今天安装了sql server 2008 R2,安装成功之后我打开软件登陆都没问题,但是一展开选项就弹出错误提示框: 参数名:viewInfo 不能为空 (Microsoft SqlServer Ma ...
- linux-shell——01
没有什么好的标题,只是一些随笔.我用的是linux虚拟机,red hat 7 一:nat模式使得虚拟机可以访问外网,但是这种模式下只可以访问外网,但外面的不能访问里面 首先将虚拟机的网络连接改为nat ...
- python使用网易邮箱发邮件
# -*- coding: UTF-8 -*- import smtplib from email.mime.text import MIMEText import email.mime.multip ...
- 第四模块:网络编程进阶&数据库开发 口述
进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 子进程死了之后 ,父进程关闭的时候要清理掉子进程的僵尸进程(收尸),孤儿进程是指父进程先死掉了的,交给init管理. join() 等待子进 ...
- Parameter 'limit' not found. Available parameters are [arg1, arg0, pa
mybatis代码报错,这是因为mapper识别不了limit,需要替换成 LIMIT #{arg0},#{arg1}