codeforces802 A-O Helvetic Coding Contest 2017 online mirror

A  Heidi and Library (easy)

水题 同B

#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn=1000000;
int n,k,a[maxn],num;
bool ex[maxn],need[maxn];
int main()
{//freopen("t.txt","r",stdin);
scanf("%d%d",&n,&k);
num=0;
memset(ex,0,sizeof(ex));
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int ans=0;
for(int i=0;i<n;i++)
{
if(ex[a[i]]) continue;
if(num<k)
{
num++;
ans++;
ex[a[i]]=true;
}
else
{
int sum=0;
memset(need,0,sizeof(need));
for(int j=i+1;j<n&&sum<k-1;j++)
{
if(!ex[a[j]])continue; if(need[a[j]]==false)sum++;
need[a[j]]=true;
}
for(int j=1;j<=n;j++)
{
if(ex[j]&&(!need[j])){ex[j]=false;ex[a[i]]=true;ans++;break;}
}
}
}
printf("%d\n",ans);
return 0;
}

  

B  Heidi and Library (medium)

经典的内存管理OPT算法

不过基本没有实际应用价值,因为操作系统不可能知道之后要调用哪些内存。

用map或者堆都可以实现 堆会快很多

map版本

#include <bits/stdc++.h>
using namespace std;
set<int> s;
int n,cs,k,c[400400],ne[400400],la[400400],cc; int main(){
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++)scanf("%d",&c[i]);
for(int i=n-1;i>=0;i--){
if(!la[c[i]])ne[i]=1e6,la[c[i]]=i;
else ne[i]=la[c[i]],la[c[i]]=i;
}
for(int i=0;i<n;i++){
if(s.count(i)){s.erase(i),s.insert(ne[i]);continue;}
if((int)s.size()<k)
s.insert(ne[i]),cc++;
else
s.erase(--s.end()),s.insert(ne[i]),cc++;
}
printf("%d\n",cc);
}

 优先队列版本

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
#include<deque>
#include<queue>
using namespace std;
const int maxn=500000;
int n,k,a[maxn],num,ne[maxn],ls[maxn];
bool ex[maxn];
priority_queue<int>que;
int main()
{//freopen("t.txt","r",stdin);
while(!que.empty())que.pop();
scanf("%d%d",&n,&k);
num=0;
memset(ex,0,sizeof(ex));
for(int i=0;i<n;i++)scanf("%d",&a[i]); for(int i=n-1;i>=0;i--)
{
if(!ls[a[i]])ls[a[i]]=1e+8;
ne[i]=ls[a[i]];
ls[a[i]]=i;
}
int ans=0;
int j=1;
int maxv=0,max2v=0;
for(int i=0;i<n;i++)
{
if(ex[i]) {
while(que.size()>0&&que.top()<=i)que.pop();
ex[i]=false;
if(ne[i]<=n)ex[ne[i]]=true;
que.push(ne[i]);
continue;
}
if(num<k)
{
num++;
ans++;
if(ne[i]<=n)ex[ne[i]]=true;
que.push(ne[i]);
}
else
{
int nowv=que.top();
que.pop();
ans++;
if(nowv<=n)ex[nowv]=false;
if(ne[i]<=n)ex[ne[i]]=true;
que.push(ne[i]);
}
}
printf("%d\n",ans);
return 0;
}

  

Heidi and Library (hard)

费用流

考虑最暴力的方法,每次调用新的书都直接购买,这多半不是最优解。

有没有办法优化到最优解呢?

考虑对于书架上的每一个位置,让它在恰当的时候继续持有书,在恰当的时候购买新的书,这样我们就能找到最优解了。

对于相同的书,连一条费用为-c[]的边(持有即相当于不用买新的所以答案-c[]),不同的书连一条费用为0的边.

#include<bits/stdc++.h>
using namespace std; typedef long long LL; #define N 200020 const LL INF = 1e9; int nxt[N], cost[N], cap[N], to[N], head[N], cnt; void init(){
memset(head, -1, sizeof head);
} void add_Edge(int S, int T, int c, int w){
nxt[cnt] = head[S], to[cnt] = T, cap[cnt] = c, cost[cnt] = w, head[S] = cnt ++;
nxt[cnt] = head[T], to[cnt] = S, cap[cnt] = 0, cost[cnt] = -w, head[T] = cnt ++;
} int prv[N], vis[N];
LL dist[N]; LL SPFA(int S, int T, int vet){
queue <int> Q;
fill(dist, dist + vet, INF);
fill(prv, prv + vet, -1);
dist[S] = 0, Q.push(S), vis[S] = true;
while(!Q.empty() ){
int x = Q.front();
Q.pop(), vis[x] = false;
for(int id = head[x]; ~id; id = nxt[id]) if( cap[id] ){
int y = to[id];
if(dist[y] > dist[x] + cost[id]){
dist[y] = dist[x] + cost[id];
prv[y] = id;
if(!vis[y]) Q.push(y), vis[y] = true;
}
}
} if(!~prv[T]){ return INF; } int cur = T;
while( cur != S ) {
cur = prv[cur];
cap[cur] --;
cap[cur xor 1] ++;
cur = to[cur xor 1];
}
return dist[T];
} int a[N], c[N], n, m; int main(){
//freopen("t.txt", "r", stdin); scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", a + i);
for(int i = 1; i <= n; i ++) scanf("%d", c + i); init(); LL ans = 0;
int S = n + 1, T = 2 * n + 2;
for(int i = 1; i <= n; i ++){
ans += c[a[i]];
add_Edge(S, i, 1, 0);
add_Edge(i, S + i, 1, -INF);
for(int j = i + 1; j <= n; j ++){
if(a[i] == a[j]) add_Edge(i + S, j, 1, -c[a[j]]);
else add_Edge(i + S, j, 1, 0);
}
add_Edge(i + S, T, 1, 0);
} for(int step = 1; step <= m; step ++){
LL tmp = SPFA(S, T, T + 1);
if(tmp >= 0) break;
ans += tmp;
}
cout << ans + INF * n << endl;
}

  

Marmots (easy)

根据泊松分布的特点,对称轴两边的概率密度最大。

用这个特点来判断是泊松分布还是平均分布。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[250],b[250];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{ for(int i=0;i<250;i++)scanf("%d",&a[i]);
//for(int i=0;i<250;i++)scanf("%d",&b[i]);
int mina=a[0],maxa=a[0],minb=b[0],maxb=b[0];
double mida=0;
for(int i=0;i<250;i++)
{
mida+=a[i];
//minb=min(minb,b[i]);maxb=max(maxb,b[i]);
}
mida/=250.;
int sum=0,sumb=0;
double len=mida/2;
for(int i=0;i<250;i++)
{
if(a[i]>(mida-len)&&a[i]<(mida+len))sum++;
if(a[i]<=1)sumb++;
}
if(sum<180||sumb>3)printf("uniform\n");
else printf("poisson\n");
}
return 0;
}

  

Marmots (medium)

在D的基础上,首先判断是 泊松分布还是平均分布

如果是泊松分布求所有值的平均值,否则求最大值和最小值的平均值。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[250],b[250];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
for(int i=0;i<250;i++)scanf("%d",&a[i]);
//for(int i=0;i<250;i++)scanf("%d",&b[i]);
double mina=a[0],maxa=a[0],minb=b[0],maxb=b[0];
double mida=0;
for(int i=0;i<250;i++)
{
mida+=a[i];
mina=min(mina,(double)a[i]);maxa=max(maxa,(double)a[i]);
}
mida/=250.;
int sum=0,sumb=0;
double len=mida/2;
for(int i=0;i<250;i++)
{
if(a[i]>(mida-len)&&a[i]<(mida+len))sum++;
if(a[i]<=1)sumb++;
}
if(sum<180||sumb>3)//printf("uniform\n");
{
printf("%.0lf\n",(mina+maxa)/2+0.5);
}
else //printf("poisson\n");
{
printf("%.0lf\n",mida+0.5);
}
}
return 0;
}

  

Marmots (hard)

由于出现了负数,所以D中简单粗暴的方法不可取了。

不过数据并没有变复杂,由于平均分布相对于泊松分布更加离散,所以方差会有明显的区别。

利用方差来判断,就不怕负数了。

#include<bits/stdc++.h>
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,a,b) for (int i=a;i>=b;i--)
using namespace std; inline int read() {
int x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+(ch^48); ch=getchar();}
return x*f;
} const int N = 251;
const int P = 1005;
const double e = 2.718281828459045235360287471352; int a[N];
double tp1[P<<1],tp2[P<<1]; int main() { int T=read();
while (T--) {
int mx=0;
double mean=0; rep(i,1,250) a[i]=read(),mean+=a[i],mx=max(mx,a[i]);
double D=0; mean/=250; rep(i,1,250) D+=a[i]*a[i];
D/=(double)250; D-=mean*mean;
double sigma = sqrt(D);
if (mx/sigma<=1.9) puts("uniform"); else puts("poisson");
} return 0;
}

  

Fake News (easy)

公共子序列问题 O(N^2)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<cstring>
using namespace std;
int dp[1000][1000];
int LCS(int n1,int n2,string s1,string s2)
{
for(int i=0;i<n1;i++)
for(int j=0;j<n2;j++)
{
if(i>0)dp[i][j]=dp[i-1][j];
if(j>0&&dp[i][j-1]>dp[i][j])dp[i][j]=dp[i][j-1];
if(s1[i]==s2[j])
{
if(i==0||j==0)dp[i][j]=1;
else dp[i][j]=dp[i-1][j-1]+1;
}
}
return dp[n1-1][n2-1];
}
int main()
{//freopen("t.txt","r",stdin);
ios::sync_with_stdio(false);
string s1,s2;
s2="heidi";
while(cin>>s1)
{
memset(dp,0,sizeof(dp));
int len=LCS(s1.length(),s2.length(),s1,s2);
if(len==5)printf("YES\n");
else printf("NO\n");
s1.clear();s2.clear();
}
return 0;
}

  

Fake News (medium)

很简单的一道计数题 直接看代码吧~

#include<cstdio>
#include<algorithm>
using namespace std;
int Comb[110][6], C[110], S;
int main(){
int i, j;
for(i=0;i<=45;i++){
Comb[i][0]=1;
for(j=1;j<=5&&j<=i;j++)Comb[i][j]=Comb[i-1][j]+Comb[i-1][j-1];
}
scanf("%d",&S);
for(i=45;i>=5;i--){
while(S>=Comb[i][5]){
C[i]++;
S-=Comb[i][5];
}
}
for(i=0;i<45;i++){
while(C[i]--)printf("b");
printf("a");
}
printf(" aaaaab\n");
}

  

Fake News (hard)

后缀数组+记忆化搜索

很有趣的一道后缀数组题

题目的意思就是让我们求一个字符串L所有子串在这个串中出现的次数。

这种问题用脚指头想都知道肯定要上后缀数组啦!

对于数组height[l...r] 其中的最小值就是他们的公共前缀的长度,而这个公共前缀就是L的一个唯一的子串。r-l+1就是它出现的次数。(ps:不懂height数组的自行学习后缀数组再来看)

怎样高效统计呢?

对于height[0,len(L)-1]我们能否高效的找到它的最小值?可以。

那么假设最小值的位置是mid 然后我们把height分成l..mid mid+1....r分别计算,那么怎么合并呢?

两个子片段的公共最小Height值就是他们的公共前缀长度,我们可以知道这个公共前缀出现的次数,但是同时要排除他们在字串中贡献的值。

太难描述了,具体转移方法看代码吧。

注意,mid一定是最小值所在的位置,不可以随意划分height数组,那样是错的。

求mid不能太暴力,会TLE。

#include <iostream>
#include <cstring>
#include <cstdio>
#include<vector>
using namespace std; const int MAX = 100500;
const int nMAX = 105;
const int mMAX = 1005; int strnum;
char str[MAX];
int source[MAX];
int sa[MAX], rk[MAX], height[MAX];
int wa[MAX], wb[MAX], wv[MAX], wd[MAX];
bool vis[nMAX];
int id[MAX];
int anslen, anspos[mMAX], ansnum;
const int MAXN=200000+100;
void radix(int *str,int *a,int *b,int n,int m)
{
static int count[MAXN];
memset(count,0,sizeof(count));
for(int i=0;i<n;++i)++count[str[a[i]]];
for(int i=1;i<=m;++i)count[i]+=count[i-1];
for(int i=n-1;i>=0;--i)b[--count[str[a[i]]]]=a[i];
} void sorted_suffix_array(int *str,int *sa,int n,int m)
{
static int rank[MAXN],a[MAXN],b[MAXN];
for(int i=0;i<n;++i)rank[i]=i;
radix(str,rank,sa,n,m); rank[sa[0]]=0;
for(int i=1;i<n;++i)rank[sa[i]]=rank[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]);
for(int i=0;(1<<i) <n;++i)
{
for(int j=0;j<n;++j)
{
a[j]=rank[j]+1;
b[j]=j+(1<<i)>=n? 0:rank[j+(1<<i)]+1;
sa[j]=j;
}
radix(b,sa,rank,n,n);
radix(a,rank,sa,n,n);
rank[sa[0]]=0;
for(int j=1;j<n;++j)
{
rank[sa[j]]=rank[sa[j-1]]+(a[sa[j-1]]!=a[sa[j]]||b[sa[j-1]]!=b[sa[j]]);
}
}
} void calc_height(int *str,int *sa,int *h,int n)
{
static int Rank[MAXN];
int k=0;
h[0]=0;
for(int i=0;i<n;++i)Rank[sa[i]]=i;
for(int i=0;i<n;++i)
{
k= k==0?0:k-1;
if(Rank[i]!=0)
while(str[i+k]==str[sa[Rank[i]-1]+k])++k;
h[Rank[i]]=k;
}
}
int stlen;
long long dp(long long l,long long r,long long &summ,vector<int>&nemi,int flag)
{ if(l==r){summ=(long long)stlen-(long long)sa[l];return summ;}
int mid=-1;
vector<int>nemr;
if(flag!=-1)mid=nemi[flag]-1;
else
{
nemi.push_back(l+1);
for(int i=l+1;i<r;i++)
{
if(height[i+1]<height[nemi[(int)nemi.size()-1]])nemi.push_back(i+1);
}
flag=(int)nemi.size()-1;
mid= nemi[flag]-1;
} long long sum1,sum2;
long long int minh=min(min(dp(l,mid,sum1,nemi,flag-1),dp(mid+1,r,sum2,nemr,-1)),(long long)height[mid+1]);
summ=sum1+sum2+minh*(r-l+1)*(r-l+1)-minh*(mid-l+1)*(mid-l+1)-minh*(r-mid)*(r-mid);
nemr.clear();
return minh;
}
long long int solve(char *st)
{
stlen=strlen(st);
for(int i=0;i<stlen;i++)
source[i]=st[i]-'a'+1;
sorted_suffix_array(source,sa,(int)stlen,126);
calc_height(source,sa,height,(int)stlen);
height[0]=1e+8; long long int ans=0;
vector<int>mi;
mi.clear();
dp(0,stlen-1,ans,mi,-1); return ans;
} int main()
{//freopen("t.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",&str);
printf("%I64d\n",solve(str));
}
return 0;
}

  

Send the Fool Further! (easy)

水题

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<cstring>
using namespace std;
vector<int>adj[200];
int w[200][200];
int dist[200];
void dfs(int cur,int fa,int len)
{
for(int i=0;i<adj[cur].size();i++)
{
int ne=adj[cur][i];
if(ne==fa)continue;
dist[ne]=min(dist[ne],len+w[cur][ne]);
dfs(ne,cur,len+w[cur][ne]);
}
}
int main()
{//freopen("t.txt","r",stdin);
int n;
scanf("%d",&n);
int u,v;
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&u,&v);
scanf("%d",&w[u][v]);
w[v][u]=w[u][v];
adj[u].push_back(v);
adj[v].push_back(u);
}
for(int i=1;i<n;i++)
dist[i]=99999999;
dist[0]=0;
dfs(0,-1,0);
int ans=0;
for(int i=0;i<n;i++)
ans=max(ans,dist[i]);
printf("%d\n",ans);
return 0;
}

  

Send the Fool Further! (medium)

比较有趣的树形DP

考虑最优解,必有两种情况,要么在0结束,要么不在0结束。对于其他节点也是一个道理。

所以设dp[i][bool]为从i出发,的最优解,bool为0则最后回到i否则不用回到i

转移方程直接看程序吧 很简单。

#include <bits/stdc++.h>
using namespace std; const int maxn = 200000;
int dp[maxn][2];
vector< pair<int,int> > E[maxn];
int n,k; bool cmp(const pair<int,int> &a, const pair<int,int> &b){
return (a.first > b.first);
} void dfs(int u, int p){
vector< pair<int,int> > c;
set<int> st; for(auto e: E[u]){
int v = e.first;
int cst = e.second;
if(v == p) continue;
dfs(v,u);
c.push_back({dp[v][0] + cst,v});
} sort(c.begin(), c.end(), cmp);
int tk = min(k-1, (int)(c.size()));
for(int i = 0; i < tk; i++){
dp[u][0] += c[i].first;
st.insert(c[i].second);
} int extra = 0;
if(tk != (int)(c.size()))
extra = c[tk].first; for(auto e: E[u]){
int v = e.first;
int cst = e.second;
if(v == p) continue; if(st.count(v) == 0)
dp[u][1] = max(dp[u][1], dp[v][1] + dp[u][0] + cst);
else
dp[u][1] = max(dp[u][1], dp[u][0] - dp[v][0] + extra + dp[v][1]);
}
st.clear();
c.clear();
} int main(){
scanf("%d%d", &n, &k);
for(int i = 1; i < n; i++){
int u,v,c;
scanf("%d%d%d", &u, &v, &c);
E[u].push_back({v,c});
E[v].push_back({u,c});
}
dfs(0,-1);
cout << max(dp[0][0], dp[0][1]) << "\n";
return 0;
}

  

Send the Fool Further! (hard)

这道题题意说的不是很清楚 总的来说是让我们求E(0)

E(0)和E(v)有线性关系,v是0的孩子。

所以,暴力解方程组的方法是可以求出来的。但是复杂度太高O(n^3)

有没有聪明一点的方法呢?

还是考虑E(0)和E(v)的关系

E(v)由它的孩子和E(0)线性组合而成。假设E(v)不考虑0的情况下期望为G(v)G(v)可以在dfs()的过程中求出来。

我们通过一定的代数变形可以直接由G(v)推出E(v)

嗯。。大致就是这样。。还是那句话 近世代数太重要了。

代码很清晰

直观的看的话 在树上求解问题,最关键的就是找出递归关系,

也就是对于当前节点求解(做到)不需考虑它的父亲部分(这样我们离答案就很近了因为最后的答案G【0】就是不需要考虑父亲的)。

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <string>
#define SIZE 100005
#define MOD 1000000007 using namespace std;
typedef long long int ll; struct edge
{
int to,cost;
edge(int to=0,int cost=0):to(to),cost(cost){}
};
vector <edge> vec[SIZE];
ll F[SIZE],G[SIZE];
int nd[SIZE];
int n; ll mpow(ll m,ll t)
{
if(t==0) return 1LL;
ll ret=mpow(m*m%MOD,t/2);
if(t%2==1) ret=ret*m%MOD;
return ret;
}
ll inv(ll m)
{
return mpow(m,MOD-2);
}
void dfs(int v=0,int p=-1)
{
if(vec[v].size()==1)
{
F[v]=G[v]=0;
return;
}
ll sumG=0,sumF=vec[v].size();
for(int i=0;i<vec[v].size();i++)
{
edge e=vec[v][i];
sumG+=e.cost;
if(sumG>=MOD) sumG-=MOD;
if(e.to!=p)
{
dfs(e.to,v);
sumG+=G[e.to];
if(sumG>=MOD) sumG-=MOD;
sumF-=F[e.to];
if(sumF<0) sumF+=MOD;
}
}
ll g=inv(sumF);
F[v]=g;
G[v]=g*sumG%MOD;
}
int main()
{ freopen("t.txt","r",stdin);
scanf("%d",&n);
for(int i=0;i<n-1;i++)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
vec[a].push_back(edge(b,c));
vec[b].push_back(edge(a,c));
}
dfs();
printf("%lld\n",G[0]);
return 0;
}

  

April Fools' Problem (easy)

每个序列排序后前k个数的和

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
int num[3000];
int main()
{//freopen("t.txt","r",stdin);
int n,m,t;
int mins=-1;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{ scanf("%d",&num[i]);
}
sort(num,num+n);
int ans=0;
for(int i=0;i<m;i++)
ans+=num[i];
printf("%d\n",ans);
return 0;
}

April Fools' Problem (medium)

很有趣的一道贪心题。

给定两个正整数序列A和B

求两个A和B的长度为k的子序列 a和b满足 a中的第i个元素在A中的位置<= b中的第i个元素在B中的位置 并且和最小。

用贪心的方法,先求一个最小的合法解 a[i]和b[j]且 j>=i,然后他们之间[i...j]就可以放反向的数对了也就是在找最小解的时候可以允许j<i了 。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL ;
const int maxn=3000;
LL a[maxn],b[maxn],va[maxn],vb[maxn],verse[maxn];
int n,k;
int main()
{//freopen("t.txt","r",stdin);
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)scanf("%I64d",&a[i]);
for(int i=0;i<n;i++)scanf("%I64d",&b[i]);
LL ans=0;
b[n]=1e+18;
while(k--)
{int ra=-1,rb;
for(int i=n-1,j=n,minb=n;i>=0;i--)
{
if(j>i)j=i;
if(b[j]<b[minb]&&!vb[j])minb=j; while((j-1)>=0&&verse[j-1])if(b[--j]<b[minb]&&!vb[j])minb=j;
if(!va[i]&&(ra==-1||a[i]+b[minb]<a[ra]+b[rb]))ra=i,rb=minb;
}
ans+=a[ra]+b[rb];va[ra]++;vb[rb]++;
for(int i=ra;i<rb;i++)verse[i]++;
for(int i=rb;i<ra;i++)verse[i]--;
}
printf("%I64d\n",ans);
return 0;
}

  

April Fools' Problem (hard)

题意和N一样 数据提高到了500000 非常有趣的一道优化题

显然N中我们O(n^2)的算法要TLE

有什么办法优化到O(nlogn)么?

1.首先考虑当前已经选定了N个题目以及他们合法的打印时间,对于以后可选的打印时间,可以用来优化答案。O(n)

2.那么主要问题就变成了如何选取恰当的N个初始题目。

我们用二分的方法选取一个阀值mid 比它更优的 我们才让它成为备选题目,这样不断二分mid 总会找到一个最恰当的mid使得选中的题目正好是m个最优的。

当然如果出现比m多的情况说明他们是相等的题目和打印时间。

看代码吧 很清晰。

#include <bits/stdc++.h>
using namespace std; typedef long long LL; #define N 500050 priority_queue <LL, vector <LL>, greater<LL> > Qa;
priority_queue <LL> Qb; LL a[N], b[N];
int n, m; const LL INF = 1e13; int main() {
// freopen("in.txt", "r", stdin); scanf("%d %d", &n, &m); for (int i = 1; i <= n; i ++) scanf("%I64d", a + i);
for (int i = 1; i <= n; i ++) scanf("%I64d", b + i); LL st = 0, en = INF, ans = 0; while (st <= en ) {
LL mid = (st + en) >> 1;
while ( !Qa.empty() ) Qa.pop();
while ( !Qb.empty() ) Qb.pop();
LL tmp = 0;
int sz = 0;
for (int i = 1; i <= n; i ++) {
Qa.push(a[i]);
LL tmp1 = Qa.top() + b[i] - mid;
LL tmp2 = Qb.empty() ? INF : b[i] - Qb.top();
if (tmp1 <= tmp2 && tmp1 <= 0) {
tmp += tmp1; sz ++;
Qb.push(b[i]);
Qa.pop();
}
else if (tmp2 < tmp1 && tmp2 < 0){
tmp += tmp2;
Qb.pop();
Qb.push(b[i]);
}
} if (sz >= m) {
ans = tmp + m * mid;
en = mid - 1;
}
else {
st = mid + 1;
}
} cout << ans << endl;
}

  

Codeforces 802 补题的更多相关文章

  1. Codeforces VP/补题小记 (持续填坑)

    Codeforces VP/补题小记 1149 C. Tree Generator 给你一棵树的括号序列,每次交换两个括号,维护每次交换之后的直径. ​ 考虑括号序列维护树的路径信息和,是将左括号看做 ...

  2. Educational Codeforces Round 24 CF 818 A-G 补题

    6月快要结束了 期末也过去大半了 马上就是大三狗了 取消了小学期后20周的学期真心长, 看着各种北方的学校都放假嗨皮了,我们这个在北回归线的学校,还在忍受酷暑. 过年的时候下定决心要拿块ACM的牌子, ...

  3. 【cf补题记录】Codeforces Round #608 (Div. 2)

    比赛传送门 再次改下写博客的格式,以锻炼自己码字能力 A. Suits 题意:有四种材料,第一套西装需要 \(a\).\(d\) 各一件,卖 \(e\) 块:第二套西装需要 \(b\).\(c\).\ ...

  4. 【cf补题记录】Codeforces Round #607 (Div. 2)

    比赛传送门 这里推荐一位dalao的博客-- https://www.cnblogs.com/KisekiPurin2019/ A:字符串 B:贪心 A // https://codeforces.c ...

  5. 2017河工大校赛补题CGH and 赛后小结

    网页设计课上实在无聊,便开始补题,发现比赛时候僵着的东西突然相通了不少 首先,"追妹"这题,两个队友讨论半天,分好多种情况最后放弃(可是我连题目都没看啊),今天看了之后试试是不是直 ...

  6. 4.30-5.1cf补题

    //yy:拒绝转载!!! 悄悄告诉你,做题累了,去打两把斗地主就能恢复了喔~~~ //yy:可是我不会斗地主吖("'▽'") ~~~那就听两遍小苹果嘛~~~ 五一假期除了花时间建模 ...

  7. 【补题记录】ZJU-ICPC Summer Training 2020 部分补题记录

    补题地址:https://zjusummer.contest.codeforces.com/ Contents ZJU-ICPC Summer 2020 Contest 1 by Group A Pr ...

  8. hdu5017:补题系列之西安网络赛1011

    补题系列之西安网络赛1011 题目大意:给定一个椭球: 求它到原点的最短距离. 思路: 对于一个椭球的标准方程 x^2/a^2 + y^2/b^2 +z^2/c^2=1 来说,它到原点的最短距离即为m ...

  9. 2018 HDU多校第四场赛后补题

    2018 HDU多校第四场赛后补题 自己学校出的毒瘤场..吃枣药丸 hdu中的题号是6332 - 6343. K. Expression in Memories 题意: 判断一个简化版的算术表达式是否 ...

随机推荐

  1. MySql 基础 基本使用方法

    安装MySQL linux安装:阿里云服务器ecs配置之安装mysqlwindows安装: 解压 管理员身份进cmd执行解压目录下的可执行文件 初始化 D:\mysql-8.0.12-winx64\m ...

  2. Django——配置服务器上线

    使用UWSGI和NGINX配置项目上线 首先你得有一个拿得出手的项目 其次,购买了域名,也备案成功了 将settings.py中的DEBUG设置为False 配置Uwsgi 在项目(哪里都可以)中创建 ...

  3. jQuery学习之------选择器

    a.id选择器 <div id=”test1”></div> var div1=$(“#test1”);                //同css的写法一样id选择器用#号实 ...

  4. CodeForces 221D Little Elephant and Array

    Little Elephant and Array Time Limit: 4000ms Memory Limit: 262144KB This problem will be judged on C ...

  5. Node.js & module system

    Node.js & module system Node.js v10.9.0 Documentation https://nodejs.org/api/modules.html#module ...

  6. Ubuntu12.04之SSH

    Ubuntu 12.04 关于SSH的知识 (1)安装完ubuntu系统12.04. (2)查看网络配置,输入命令ip addr后,显示有IP地址. (3)使用SSH终端工具Xshell连接系统,发现 ...

  7. POJ 1804 逆序对数量 / 归并排序

    Brainman Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 12175   Accepted: 6147 Descrip ...

  8. 显示锁ReentrantLock和Condition的使用

    一.ReentrantLock (1).java.util.concurrent.locks包中的ReentrantLock就是重入锁,它实现了Lock接口,Lock加锁和解锁都是显示的.Reentr ...

  9. 详解MySQL分区表

    当数据库数据量涨到一定数量时,性能就成为我们不能不关注的问题,如何优化呢? 常用的方式不外乎那么几种: 1.分表,即把一个很大的表达数据分到几个表中,这样每个表数据都不多. 优点:提高并发量,减小锁的 ...

  10. IE插件

    在OA上要直接查看word等公告文件,就必须安装office控件.要安装office控件,需要在IE浏览器中做相应的设置.如何设置呢,下面由小编具体介绍下. 工具/原料   OA IE浏览器 方法/步 ...