来自FallDream的博客,未经允许,请勿转载,谢谢,


第一次在cf上打acm...和同校大佬组队打

总共15题,比较鬼畜,最后勉强过了10题。

AB一样的题目,不同数据范围,一起讲吧

你有一个背包,最多装k本书,你在第i天需要拥有一本编号ai的书,但是你可以去商店购买并加入背包。

问你至少要买多少本书?n,k<=400000

显然可以贪心,留下下一次需要的时间最早的书就行了。

#include<iostream>
#include<cstdio>
#include<queue>
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
#define INF 2000000000
#define MN 400000
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} priority_queue<pa> q;
int n,k,a[MN+],ne[MN+],la[MN+],ans=;
bool in[MN+]; int main()
{
n=read();k=read();
for(int i=;i<=n;++i) a[i]=read();
for(int i=n;i;--i)
{
ne[i]=la[a[i]]?la[a[i]]:INF;
la[a[i]]=i;
}
for(int i=;i<=n;++i)
{
if(in[a[i]])
++k,q.push(mp(ne[i],a[i]));
else
{
++ans;
while(q.size()==k) in[q.top().second]=,q.pop();
q.push(mp(ne[i],a[i]));
in[a[i]]=;
} }
cout<<ans;
return ;
}

C. 还是同样的题面,只不过每本书要的钱不一样了,n,k<=80

把一本书留到下一次用看作一个区间覆盖,发现这就是一道k可重区间问题,费用流建图即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define S 0
#define MN 80
#define T 81
#define INF 2000000000
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} int d[MN+],n,k,head[MN+],cnt=,a[MN+],c[MN+],ans=,pi=,la[MN+];
struct edge{int to,next,w,c;}e[MN*MN];
bool inq[MN+],mark[MN+];
deque<int> q; inline void ins(int f,int t,int w,int c)
{
e[++cnt]=(edge){t,head[f],w,c}; head[f]=cnt;
e[++cnt]=(edge){f,head[t],,-c};head[t]=cnt;
} bool modlabel()
{
for(int i=S;i<=T;++i) d[i]=INF;
d[T]=;inq[T]=;q.push_front(T);
while(!q.empty())
{
int x=q.front();q.pop_front();
for(int i=head[x];i;i=e[i].next)
if(e[i^].w&&e[i^].c+d[x]<d[e[i].to])
{
d[e[i].to]=d[x]+e[i^].c;
if(!inq[e[i].to])
{
inq[e[i].to]=;
if(d[e[i].to]<d[q.size()?q.front():]) q.push_front(e[i].to);
else q.push_back(e[i].to);
}
}
inq[x]=;
}
for(int i=S;i<=T;++i)
for(int j=head[i];j;j=e[j].next)
e[j].c+=d[e[j].to]-d[i];
return pi+=d[S],d[S]<INF;
} int dfs(int x,int f)
{
if(x==T) return ans+=pi*f,f;
int used=;mark[x]=;
for(int i=head[x];i;i=e[i].next)
if(e[i].w&&!e[i].c&&!mark[e[i].to])
{
int w=dfs(e[i].to,min(f-used,e[i].w));
used+=w;e[i].w-=w;e[i^].w+=w;
if(used==f) return used;
}
return used;
} int main()
{
n=read();k=read()-;
for(int i=;i<=n;++i) a[i]=read();
for(int i=;i<=n;++i) c[i]=read();
for(int i=;i<=n;++i) ans+=c[a[i]];
ins(S,,k,);ins(n,T,k,);
for(int i=;i<n;++i) ins(i,i+,INF,);
for(int i=;i<=n;++i)
{
if(la[a[i]])
{
if(la[a[i]]==i-) ans-=c[a[i]];
else ins(la[a[i]]+,i,,-c[a[i]]);
}
la[a[i]]=i;
}
while(modlabel())
do memset(mark,,sizeof(mark));
while(dfs(S,INF));
cout<<ans;
return ;
}

DEF比较牛逼 D题wa了个几十次,还剩半分钟的时候居然过了  感觉这种奇奇怪怪的题并没有发言权...

G题是送分的

H题

给你一个数字n(<=1000000),要求你构造两个字符串,使得第二个字符串作为子序列在第一个字符串中的出现次数恰好是n次,且第一个字符串的长度不超过200

考虑用组合数来解决。让第二个串为'aaaaab',那么第一个串中每个B的贡献都是他前面的a的个数选出5个的组合数。只要选择适当的地方插入就行了。

#include<iostream>
#include<cstdio>
#define MN 50
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} int num[MN+],n,C[MN+][]; int main()
{
n=read();C[][]=;
for(int i=;i<=MN;++i)
{
C[i][]=;
for(int j=;j<=;++j)
C[i][j]=C[i-][j]+C[i-][j-];
}
for(int i=MN;i>=;--i)
while(n>=C[i][]) n-=C[i][],++num[i];
for(int i=;i<=MN;putchar('a'),++i)
for(int j=;j<=num[i];++j) putchar('b');
printf(" aaaaab");
return ;
}

I

给定一个长度为n字符串,求每个不同子串的出现次数的平方。

T(T<=10)组数据,n<=100000

建出后缀自动机之后,简单dp一下就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
}
int c[][],step[],fail[];
long long val[];long long sum[];
char s[];
int cnt=,last=,n; void ins(int x)
{
int p=last,np=++cnt;step[np]=step[last]+;val[np]=;
for(;p&&!c[p][x];p=fail[p])c[p][x]=np;
if(!p)fail[np]=;
else
{
int q=c[p][x];
if(step[q]==step[p]+) fail[np]=q;
else
{
int nq=++cnt;step[nq]=step[p]+;
for(int i=;i<;i++)c[nq][i]=c[q][i];
fail[nq]=fail[q];fail[q]=fail[np]=nq;
for(;c[p][x]==q;p=fail[p])c[p][x]=nq;
}
}
last=np;
} int v[],rk[];
void work()
{
memset(v,,sizeof(v));
for(int i=;i<=cnt;i++)v[step[i]]++;
for(int i=;i<=n;i++)v[i]+=v[i-];
for(int i=cnt;i;i--) rk[v[step[i]]--]=i;
for(int i=cnt;i;i--) val[fail[rk[i]]]+=val[rk[i]];
}
bool vis[];
long long Dfs(int x)
{
if(vis[x]) return sum[x];
if(x!=)sum[x]=1LL*val[x]*val[x];vis[x]=;
for(int i=;i<;++i) if(c[x][i])
sum[x]+=Dfs(c[x][i]);
return sum[x];
} int main()
{
for(int T=read();T;--T)
{
memset(c,,sizeof(c));
memset(fail,,sizeof(fail));
memset(step,,sizeof(step));
memset(vis,,sizeof(vis));
memset(sum,,sizeof(sum));
memset(val,,sizeof(val));
cnt=last=;
scanf("%s",s+);n=strlen(s+);
for(int i=;s[i];ins(s[i++]-'a'));
work();
cout<<Dfs()<<endl;
}
return ;
}

J是送分的

K

给定一棵树,有边权,你要从1号点出发,要求每个点经过次数不超过k的前提下,经过的边的权值和最大(多次经过只算一次)

n<=100000

显然是一道树形dp,用f[i]表示回到i号点的最大答案,f2[i]表示不回来的最大答案,然后用优先队列保存前k大就行了。

#include<iostream>
#include<cstdio>
#include<queue>
#define mp(x,y) make_pair(x,y)
#define pa pair<int,int>
#define MN 100000
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} int n,k,cnt=,f[MN+],f2[MN+],head[MN+],mark[MN+];
struct edge{int to,next,w;}e[MN*+];
priority_queue<pa,vector<pa>,greater<pa> > q[MN+],q2[MN+]; inline void ins(int f,int t,int w)
{
e[++cnt]=(edge){t,head[f],w};head[f]=cnt;
e[++cnt]=(edge){f,head[t],w};head[t]=cnt;
} void Dp(int x,int fa)
{
for(int i=head[x];i;i=e[i].next)
if(e[i].to!=fa)
{
Dp(e[i].to,x);
q[x].push(mp(f[e[i].to]+e[i].w,e[i].to));
}
int mx=,mx2=,mm;
while(q[x].size()>k) q[x].pop();
if(q[x].size()==k) mm=q[x].top().first,mark[q[x].top().second]=x; else mm=;
while(q[x].size()>k-) q[x].pop();
while(!q[x].empty())
{
pa now=q[x].top();
f[x]+=now.first;
mark[now.second]=x;
q[x].pop();
}
for(int i=head[x];i;i=e[i].next)
if(e[i].to!=fa)
{
if(mark[e[i].to]==x)
mx=max(mx,f2[e[i].to]-f[e[i].to]);
else mx2=max(mx2,e[i].w+f2[e[i].to]);
}
f2[x]=max(f[x],max(f[x]+mx2,f[x]+mx+mm));
} int main()
{
n=read();k=read();
for(int i=;i<n;++i)
{
int x=read()+,y=read()+,w=read();
ins(x,y,w);
}
Dp(,);
printf("%d\n",max(f[],f2[]));
return ;
}

M

给样例猜题意,输出前k小的数字的和就行了。

N

给定两个长度为n的序列,你要从每个序列中选出k个,并且满足a序列中选出的第i个的位置小等于从b序列中选出的第i个,求最小的和。

n<=2000

考虑二分一个值,并把所有数字减去那个值,通过n^2dp求出最小的情况下最多/最少选出多少个,区间包含了k时输出答案即可

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MN 2200
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} ll f[MN+][MN+],N[MN+][MN+],N2[MN+][MN+];
int a[MN+],b[MN+],n,k; int main()
{
n=read();k=read();
for(int i=;i<=n;++i) a[i]=read();
for(int i=;i<=n;++i) b[i]=read();
int l=-(1e9),r=1e9,mid;
while(l<=r)
{
mid=1LL*l+r>>;
memset(f,,sizeof(f));
for(int i=;i<=n;++i) f[][i]=f[i][]=;
for(int i=;i<=n;++i)
for(int j=i;j<=n;++j)
{
if(f[i-][j]<f[i][j]) f[i][j]=f[i-][j],N[i][j]=N[i-][j],N2[i][j]=N2[i-][j];
else if(f[i-][j]==f[i][j]) N[i][j]=max(N[i][j],N[i-][j]),N2[i][j]=min(N2[i][j],N2[i-][j]);
if(f[i][j-]<f[i][j]) f[i][j]=f[i][j-],N[i][j]=N[i][j-],N2[i][j]=N2[i][j-];
else if(f[i][j-]==f[i][j]) N[i][j]=max(N[i][j],N[i][j-]),N2[i][j]=min(N2[i][j],N2[i][j-]);
if(f[i-][j-]+a[i]-mid+b[j]-mid<f[i][j])
f[i][j]=f[i-][j-]+a[i]-mid+b[j]-mid,N[i][j]=N[i-][j-]+,N2[i][j]=N2[i-][j-]+;
else if(f[i-][j-]+a[i]-mid+b[j]-mid==f[i][j])
N[i][j]=max(N[i][j],N[i-][j-]+),N2[i][j]=min(N2[i][j],N2[i-][j-]+);
}
if(N[n][n]>=k&&N2[n][n]<=k) return *printf("%lld",f[n][n]+2LL*k*mid);
else if(N[n][n]>k) r=mid-;
else l=mid+;
}
return ;
}

O题意相同 数据范围500000

发现这就像一个二分图匹配,并且每个b之和之前的a连边,考虑二分之后用堆来贪心。

从前往后确定每一个b的匹配,往堆里加入a,这个b只能和堆顶配对,如果更优秀的话就配对。但是这可能不是最优的,所以之后还要加入-b来表示推流,更换一个b和这个a配对。

#include<iostream>
#include<cstdio>
#include<queue>
#define ll long long
#define mp(x,y) make_pair(x,y)
#define pa pair<ll,int>
#define MN 500000
using namespace std;
inline int read()
{
int x = ; char ch = getchar();
while(ch < '' || ch > '') ch = getchar();
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x;
} int A[MN+],B[MN+],n,m;ll tot;
priority_queue<pa,vector<pa>,greater<pa> > q; int Solve(int x)
{
tot=;int num=;
for(int i=;i<=n;++i)
{
q.push(mp(A[i],));
ll t=q.top().first,now=B[i]-x;
if(now+t<)
{
tot+=now+t;
q.pop();
q.push(mp(-now,));
}
}
while(!q.empty()) num+=q.top().second,q.pop();
return num;
} int main()
{
n=read();m=read();
for(int i=;i<=n;++i) A[i]=read();
for(int i=;i<=n;++i) B[i]=read();
int l=,r=2e9,mid;
while(l<=r)
{
mid=1LL*l+r>>;int num=Solve(mid);
if(num==m) return *printf("%lld\n",tot+1LL*m*mid);
if(num<m) l=mid+;
else r=mid-;
}
return ;
}

[Helvetic Coding Contest 2017 online mirror]的更多相关文章

  1. 【Codeforces】Helvetic Coding Contest 2017 online mirror比赛记

    第一次打ACM赛制的团队赛,感觉还行: 好吧主要是切水题: 开场先挑着做五道EASY,他们分给我D题,woc什么玩意,还泊松分布,我连题都读不懂好吗! 果断弃掉了,换了M和J,然后切掉了,看N题: l ...

  2. Helvetic Coding Contest 2017 online mirror (teams allowed, unrated)

    G. Fake News (easy) time limit per test 1 second memory limit per test 256 megabytes input standard ...

  3. Helvetic Coding Contest 2017 online mirror (teams allowed, unrated) J

    Description Heidi's friend Jenny is asking Heidi to deliver an important letter to one of their comm ...

  4. Helvetic Coding Contest 2017 online mirror (teams allowed, unrated) M

    Description The marmots have prepared a very easy problem for this year's HC2 – this one. It involve ...

  5. Helvetic Coding Contest 2017 online mirror (teams allowed, unrated) A

    Description Your search for Heidi is over – you finally found her at a library, dressed up as a huma ...

  6. Helvetic Coding Contest 2019 online mirror (teams allowed, unrated)

    http://codeforces.com/contest/1184 A1 找一对整数,使x^x+2xy+x+1=r 变换成一个分式,保证整除 #include<iostream> #in ...

  7. CF 690C3. Brain Network (hard) from Helvetic Coding Contest 2016 online mirror (teams, unrated)

    题目描述 Brain Network (hard) 这个问题就是给出一个不断加边的树,保证每一次加边之后都只有一个连通块(每一次连的点都是之前出现过的),问每一次加边之后树的直径. 算法 每一次增加一 ...

  8. Helvetic Coding Contest 2016 online mirror A1

    Description Tonight is brain dinner night and all zombies will gather together to scarf down some de ...

  9. Helvetic Coding Contest 2016 online mirror F1

    Description Heidi has finally found the mythical Tree of Life – a legendary combinatorial structure ...

随机推荐

  1. Vue-cli+Vue.js2.0+Vuex2.0+vue-router+es6+webpack+node.js脚手架搭建和Vue开发实战

    Vue.js是一个构建数据驱动的web界面的渐进式框架.在写这边文章时Vue版本分为1.0++和2.0++,这个是基于Vue2.0的项目. Vue-cli是构建单页应用的脚手架,这个可是官方的. Vu ...

  2. day-4 python多进程编程知识点汇总

    1. python多进程简介 由于Python设计的限制(我说的是咱们常用的CPython).最多只能用满1个CPU核心.Python提供了非常好用的多进程包multiprocessing,他提供了一 ...

  3. 【微软大法好】VS Tools for AI全攻略(2)

    接着上文,我们来讨论如何使用Azure资源来训练我们的tensorflow项目.Azure云我个人用得很多,主要是因为微软爸爸批了150刀每月的额度,我可以愉快地玩耍. 那么针对Azure,有成套的两 ...

  4. MSIL实用指南-一维数组的操作

    本篇讲解怎么生成和操作一维数组.各种数组类型创建的步骤是一样的,但是加载和保存步骤有所不同. 一.创建数组所有类型的一维数组创建都是一样的,分三步.1.加载数组长度2.生成指令 Newarr < ...

  5. io文本加密

    文本加密习题 package io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.Inpu ...

  6. Python-字符串及列表操作-Day2

    1.数据类型 1.1 变量引出数据类型 变量:用来记录状态变量值的变化就是状态的变化,程序运行的本质就是来处理一系列的变化 1.2 五大基本数据类型: 数字 字符串 列表 元组 字典 1.2.1 数字 ...

  7. Electron的代码调试

    刚接触Electron,尝试调试程序时,竟无从下手,所以把这个过程做了下记录 参考工程 根据Electron的官方文档:使用 VSCode 进行主进程调试:https://electronjs.org ...

  8. Krajee插件的用法

      第一步: <!-- 必须引入 --> link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/boots ...

  9. VS2013 堆栈溢出调查(0xC00000FD: Stack overflow)

    在调试一个代码时,执行过程中会出现如下错误(0xC00000FD: Stack overflow). 很明显是堆栈溢出了. 网上很多方法,都是通过修改设置工程配置,把堆栈调大一些,如下图. 但是堆栈到 ...

  10. Java Servlet(十一):一个servlet被10个浏览器客户端访问时会创建几个servlet实例?

    一般Servlet只初始化一次(只有一个实例).对于更多的客户端请求,Server创建新的请求和响应对象,仍然激活此Servlet的service()方法,将这两个对象作为参数传递给该方法.如此重复以 ...