Codeforces 788 (Div. 1)
788 A
题意
给你一个长度为 \(n\) 的序列 \(a\) ,定义函数
其中 \(1\le l<r\le n\)
求对于所有可能的 \(l,r,f(l,r)\) 的最大值
\((2\le n\le 100000)\)
Examples
Input
5
1 4 2 3 1
Output
3
Input
4
1 5 4 7
Output
6
解
设 \(dp[i][0]\) 为未计算当前节点能达到的最大值, \(dp[i][1]\) 为计算当前节点能达到的最大值.
每枚举一个 \(i\) ,\(ans\) 都取一遍 \(\max\)
转移方程:
dp[i][0]=max(dp[i-1][1]-s[i],0);
dp[i][1]=max(dp[i-1][0]+s[i],s[i]);
ans=max(ans,max(dp[i][0],dp[i][1]));
788 B
题意
给你一张图,有自环,无重边,找出一条路径,使得它经过所有的边,且经过这些边的其中两条恰好 \(1\) 次,经过其他边恰好 \(2\) 次。
求出所有满足条件的路径数量。
\((1\le n,m\le 10^6)\)
Examples
Input
5 4
1 2
1 3
1 4
1 5
Output
6
Input
5 3
1 2
2 3
4 5
Output
0
Input
2 2
1 1
1 2
Output
1
解
设对于一对边,如果存在一条合法路径,使这条路径经过着两条边恰好 \(1\) 次,那么我们称这一对边是合法的。
经过一番波折,我们推出:两两非自环边搭配必定合法;自环与任意一条边(可以是自环,也可以不是)搭配都合法。
最后累计。
788 C
题意
有 \(k\) 瓶不同浓度的可乐,每瓶1000mL,现在要求配一瓶浓度为 \(n\) mL/1000mL 的可乐,问最少需要几瓶。\((0 ≤ n ≤ 1000, 1 ≤ k ≤ 10^6)\)
Examples
Input
400 4
100 300 450 500
Output
2
Input
50 2
100 25
Output
3
解
将每瓶饮料的浓度减去 \(n\)
题目可以转换为求一条最短路,这条最短路上的权值之和为 \(0\) ,且长度最小
我们发现,合法的浓度不会超过 \(2000\) 种
于是用dijkstra搞一下就好了
后来发现其实只需要一个bfs!!
788 D
题意
交互题
平面上有 \(n\) 条直线,与坐标轴平行。现在,你有至多 \(3×10^5\) 次机会询问,每次询问形如 \(0\;x\;y\) ,系统将返回与这个点距离最近的直线到它的距离。
直到已知所有直线的解析式,要求输出。
\((1\le n\le 2×10^4,直线坐标,询问坐标\le 10^8)\)
Example
Input
1
1
3
2
Output
0 1 2
0 -2 -2
0 5 6
0 -2 2
1 1 2
2
0 -3
解
从点 \((-10^8,-10^8)\) 沿直线 \(y=x\) 向上询问
设询问结果为ret
如果ret==0,那么将当前位置向右上平移1距离
否则将当前位置向右上平移ret距离
这样的话会 \(\text{TLE}\) 一个点,需要加一个剪枝
就是如果当前搜到一个点ret!=0,且这个点向上100距离搜到的点ret也!=0,那么直接向上跳100距离
好了
788 E
题意
有 \(n\) 个士兵,要选5个参加比赛
选的5个人合法的条件是:设这5个人的下标为 \(i,j,k,l,p\) ,满足 \(1\le i<j<k<l<p\le n\) 且 \(a_i\le a_j = a_k = a_l ≥ a_p\) 。
现在有 \(m\) 次操作,每次操作规定某一个士兵不能作为 \(j,k,l\) 参加比赛或者能作为...参加比赛
对于每次操作,需要输出操作后选择5个人的方案数
膜 \(10^9+7\)
\((1\le n,m\le 10^5,1\le a_i\le 10^9)\)
Examples
Input
6
1 1 1 1 1 1
2
1 3
2 3
Output
1
6
Input
8
3 4 4 2 4 5 4 1
3
1 5
2 5
1 2
Output
1
6
2
解
第一步:树状数组+离散化,维护 \(pre[i],nxt[i]\) ,分别表示 \(a[i]\) 前面的数中 \(\le a[i]\) 的有多少个, \(a[i]\) 后面的数中 \(\le a[i]\) 的有多少个。
第二步:线段树,对每个离散化的 \(a[i]\) 的值开一个线段树(动态开点),每个节点维护 \(6\) 个值: \(A,B,C,AB,BC,ABC\) ,表示当前节点所表示区间选出 j,k,l,j和k,k和l,j、k和l 的方案数。
具体操作:
先预处理出未进行任何操作时的答案。
叶子节点初始值:
t[p].A=pre[l];
t[p].B=1;
t[p].C=nxt[r];
t[p].AB=t[p].BC=t[p].ABC=0;
对于每次操作,对线段树进行单点修改。
对于每次操作后的询问,查询区间 \([1,n]\) 。
Code
#include<bits/stdc++.h>
#define maxn 200003
#define mod 1000000007
using namespace std;
int Plus(long long x,long long y){return (x+=y)>=mod?x%mod:x;}
int Minus(long long x,long long y){return (x+=mod-y)>=mod?x%mod:x;}
int mul(long long x,long long y){return (x*=y)>=mod?x%mod:x;}
int n,a[maxn],mp[maxn],cntmp,pre[maxn],nxt[maxn];
namespace BIT{
int t[maxn];
void clear(){
for(int i=1;i<=n;i++)t[i]=0;
}
void add(int pos,int k){
while(pos<=n){
t[pos]+=k;
pos+=pos&-pos;
}
}
int query(int pos){
int ret=0;
while(pos){
ret+=t[pos];
pos-=pos&-pos;
}
return ret;
}
}
namespace SEG{
struct node{
int _2,_3,_4,_23,_34,_234,son[2];
node():_2(0),_3(0),_4(0),_23(0),_34(0),_234(0){son[0]=son[1]=0;}
}t[maxn*20];
int cnt,root[maxn];
void pushup(int p){
int son0=t[p].son[0],son1=t[p].son[1];
t[p]._2=Plus(t[son0]._2,t[son1]._2);
t[p]._3=Plus(t[son0]._3,t[son1]._3);
t[p]._4=Plus(t[son0]._4,t[son1]._4);
t[p]._23=Plus(mul(t[son0]._2,t[son1]._3),Plus(t[son0]._23,t[son1]._23));
t[p]._34=Plus(mul(t[son0]._3,t[son1]._4),Plus(t[son0]._34,t[son1]._34));
t[p]._234=Plus(Plus(Plus(mul(t[son0]._2,t[son1]._34),mul(t[son0]._23,t[son1]._4)),t[son0]._234),t[son1]._234);
}
void change(int& p,int l,int r,int pos,bool k){
if(p==0)p=++cnt;
if(l==r){
t[p]._2=k*pre[pos];
t[p]._3=k;
t[p]._4=k*nxt[pos];
return;
}
int mid=(l+r)>>1;
if(pos<=mid)change(t[p].son[0],l,mid,pos,k);
else change(t[p].son[1],mid+1,r,pos,k);
pushup(p);
}
int query(int p){
return t[p]._234;
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
mp[++cntmp]=a[i];
}
sort(mp+1,mp+cntmp+1);
cntmp=unique(mp+1,mp+cntmp+1)-mp-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(mp+1,mp+cntmp+1,a[i])-mp;
for(int i=1;i<=n;i++){
pre[i]=BIT::query(a[i]);
BIT::add(a[i],1);
}
BIT::clear();
for(int i=n;i>=1;i--){
nxt[i]=BIT::query(a[i]);
BIT::add(a[i],1);
}
int ans=0;
for(int i=1;i<=n;i++){
ans=Minus(ans,SEG::query(SEG::root[a[i]]));
SEG::change(SEG::root[a[i]],1,n,i,1);
ans=Plus(ans,SEG::query(SEG::root[a[i]]));
}
int Q;
scanf("%d",&Q);
while(Q--){
int mo,x;
scanf("%d%d",&mo,&x);
ans=Minus(ans,SEG::query(SEG::root[a[x]]));
if(mo==1)SEG::change(SEG::root[a[x]],1,n,x,0);
else SEG::change(SEG::root[a[x]],1,n,x,1);
ans=Plus(ans,SEG::query(SEG::root[a[x]]));
printf("%d\n",ans);
}
return 0;
}