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. Python之机器学习-朴素贝叶斯(垃圾邮件分类)

    目录 朴素贝叶斯(垃圾邮件分类) 邮箱训练集下载地址 模块导入 文本预处理 遍历邮件 训练模型 测试模型 朴素贝叶斯(垃圾邮件分类) 邮箱训练集下载地址 邮箱训练集可以加我微信:nickchen121 ...

  2. MySQL-----用户和授权管理

    用户管理: 创建用户:  create user '用户名'@'用户pc的ip地址(ip可以写精准点的,也可以是网段的,也可以写一个‘’%‘’提所有)' identified(设置密码) by '密码 ...

  3. 【05】AJAX实例-检测用户名是否存在(实例)

    AJAX实例-检测用户名是否存在   用户注册时,需要填写个人信息,其中包括用户名.当用户输入完成时,JavaScript 需要及时检测用户名是否存在,如果存在给出提示,请用户更换用户名. 当然,这个 ...

  4. 【codeforces 1109B】Sasha and One More Name

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 如果这个回文串的左半部分,字母全是一样的. 那么显然不可能再分出来了,因为不管怎么分怎么排列,最后肯定都只能和原串一样. 所以无解 其他情况下 ...

  5. STM32F407 GPIO 库函数编程套路(led与beep总结) 个人笔记

    本文由正点原子STM32F407探索者开发板的led和beep实验,总结了gpio编程的套路. 下文中以hardware 来称呼可能的硬件外设,如led或beep等. 新建项目后主要用到三个文件:ha ...

  6. MVC系统学习6—Filter

    Mvc的过滤器是特性类,可以使我们在执行Action之前,执行Action之后,执行Action发生异常时,编写相关的处理代码实现某些逻辑.下面是四个基本的Filter接口. 上面这四个基本的Filt ...

  7. 【中文排序】mysql order by 中文排序

    1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都存在. 如果这个问题不解决,那么MySQL ...

  8. 博弈论入门题 kiki's game

    Problem Description Recently kiki has nothing to do. While she is bored, an idea appears in his mind ...

  9. SQL Server Management Studio自定义快捷键

    SQL Server Management Studio支持自定义快捷键:工具->选项->键盘: 其中,Alt+F1.Ctrl+1.Ctrl+2是系统预定义的快捷键. 双击表名(或按Ctr ...

  10. UVALive7042(博弈论)

    题意: Bob和Alice在有向图内玩游戏,n个顶点,m条边. 每人一颗棋子,初始位置分别是x,y. Bob先手,轮流操作,每次只能走一条有向边. 结束条件: 1.不能操作的人输 2.两个棋子重合Bo ...