第一次挂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. poj_1284_Primitive root

    We say that integer x, 0 < x < p, is a primitive root modulo odd prime p if and only if the se ...

  2. spring-bean(全生命周期)

    作用:在初始化和销毁bean时候,做一些处理工作是调用生命周期方法 格式: <bean id=”该生命周期的名称” class=”提供方法的类的全路径” init-methood=”init” ...

  3. 侯捷《C++面向对象开发》——动手实现自己的复数类

    前言 最近在看侯捷的一套课程<C++面向对象开发>,刚看完第一节introduction之后就被疯狂圈粉.感觉侯捷所提及所重视的部分也正是我一知半解的知识盲区,我之前也写过一些C++面向对 ...

  4. scrapy--doutu

    年轻人都爱斗图,可是有时候斗图的数量比较少.就想办法收藏其他的人图片,然而只要能在doutula网页里爬取图片,是一件很棒的的事,看别人写爬斗图的爬虫程序有点麻烦,自己也来动动手,简单,实用.给大家分 ...

  5. HAN模型理解1

    HAN 模型 最开始看这个模型是看的这个解释: RNN+Attention(HAN) 文本分类 阅读笔记 - 今天做作业没的文章 - 知乎 https://zhuanlan.zhihu.com/p/4 ...

  6. Python全栈day 04

    Python全栈day 04 一.解释器/编译器 补充:编译型语言和解释型语言? # 编译型:代码写完后,编译器将其变成成另外一个文件,然后交给计算机执行. c c++,c# ,java # 解释型: ...

  7. 29-自己动手构建RequestDelegate管道

    1-使用vsCode新建个项目 2-新建RequestDelegate和Context public delegate Task RequestDelegate(Context context); p ...

  8. TouTiao开源项目 分析笔记1

    1.InitApp==>项目的入口Application 1.1.继承了MultiDexApplication 超过65K方法的APP,会遇到65535的错误.原因就是为了支持比较大型的APP而 ...

  9. 斐波那契数列(Fibonacci) iOS

    斐波那契数列Fibonacci 斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2 ...

  10. 剑指Offer - 九度1368 - 二叉树中和为某一值的路径

    剑指Offer - 九度1368 - 二叉树中和为某一值的路径2013-11-23 03:46 题目描述: 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结 ...