第一次挂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日总结:的更多相关文章

  1. NOIP2017赛前模拟11月6日—7日总结

    收获颇丰的两天··· 题目1:序列操作 给定n个非负整数,进行m次操作,每次操作给出c,要求找出c个正整数数并将它们减去1,问最多能进行多少操作?n,m<=1000000 首先暴力贪心肯定是每次 ...

  2. NOIP2017赛前模拟11月2日总结

    分数爆炸的一天··但也学了很多 题目1:活动安排 给定n个活动的开始时间与结束时间··只有一个场地··要求保留尽量多的活动且时间不冲突···场地数n<=100000 考点:贪心 直接将结束时间按 ...

  3. NOIP2017赛前模拟10月30日总结

    题目1: n个人参赛(n<=100000),每个人有一个权值··已知两个人权值绝对值之差小于等于K时,两个人都有可能赢,若大于则权值大的人赢···比赛为淘汰制,进行n-1轮·问最后可能赢的人有多 ...

  4. 11月30日《奥威Power-BI智能分析报表制作方法》腾讯课堂开课啦

    这么快一周就过去了,奥威公开课又要与大家见面咯,上节课老师教的三种报表集成方法你们都掌握了吗?大家都知道,学习的结果在于实际应用,想要熟练掌握新内容的要点就在于去应用它.正是基于这一要点,每一期的课程 ...

  5. 11月23日《奥威Power-BI报表集成到其他系统》腾讯课堂开课啦

    听说明天全国各地区都要冷到爆了,要是天气冷到可以放假就好了.想象一下大冷天的一定要在被窝里度过才对嘛,索性明天晚上来个相约吧,相约在被窝里看奥威Power-BI公开课如何?        上周奥威公开 ...

  6. 11月16日《奥威Power-BI基于SQL的存储过程及自定义SQL脚本制作报表》腾讯课堂开课啦

           上周的课程<奥威Power-BI vs微软Power BI>带同学们全面认识了两个Power-BI的使用情况,同学们已经迫不及待想知道这周的学习内容了吧!这周的课程关键词—— ...

  7. 11月09日《奥威Power-BI vs微软Power BI》腾讯课堂开课啦

    上过奥威公开课的同学可能有一个疑问:奥威Power-BI和微软Power BI是同一个吗,为什么叫同样的名字?正如这个世界上有很多个John.Jack.Marry…一样,奥威Power-BI和微软Po ...

  8. 2016年11月30日 星期三 --出埃及记 Exodus 20:21

    2016年11月30日 星期三 --出埃及记 Exodus 20:21 The people remained at a distance, while Moses approached the th ...

  9. 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 ...

随机推荐

  1. SAP标准导出功能 - 删除默认选定格式

    我们经常会使用SAP系统的标准功能导出ALV显示的数据,一般会选择电子表格. 选择电子表格之后,需要选择电子表格的具体格式. 选择格式之后点击确定,会弹出保存对话框. 如果在使用这个功能的时候,选择了 ...

  2. Navicat Premium Mac 12 破解

    破解地址:https://blog.csdn.net/xhd731568849/article/details/79751188 亲测有效

  3. 给树莓派Raspbian stretch版本修改软件源

    树莓派最新的系统版本是stretch,试了阿里和网易的软件源都不行,最后试了清华的可以 deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbia ...

  4. px与em的区别,权重的优先级

    px与em的区别,权重的优先级 PX特点:px像素(Pixel).相对长度单位.像素px是相对于显示器屏幕分辨率而言的.EM特点:1. em的值并不是固定的:2. em会继承父级元素的字体大小. 权重 ...

  5. Git使用简单总结--源自廖雪峰网站

    创建版本库git add加入到暂存区git commit -m" "加入到分支 时光机穿梭git satus查看仓库的当前状态git diff file 查看修改内容 版本回退HE ...

  6. HDU 6386 Age of Moyu

    Problem Description Mr.Quin love fishes so much and Mr.Quin’s city has a nautical system,consisiting ...

  7. NumPy库入门

    ndarray数组的元素类型 ndarray数组的创建 ndarray数组的操作 ndarray数组的运算

  8. python基础之继承实现原理、子类调用父类的方法、封装

    继承实现原理 python中的类可以同时继承多个父类,继承的顺序有两种:深度优先和广度优先. 一般来讲,经典类在多继承的情况下会按照深度优先的方式查找,新式类会按照广度优先的方式查找 示例解析: 没有 ...

  9. 8,实例化Flask的参数 及 对app的配置

    Flask 是一个非常灵活且短小精干的web框架 , 那么灵活性从什么地方体现呢? 有一个神奇的东西叫 Flask配置 , 这个东西怎么用呢? 它能给我们带来怎么样的方便呢? 首先展示一下: from ...

  10. Android webview 加载https网页显示空白

    http://www.2cto.com/kf/201110/108836.html 这个网址讲的不错. 设置webview支持https的方法: webView.setWebViewClient(ne ...