来自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. python3变量和数据类型

        变量和数据类型 知识点 python 关键字 变量的定义与赋值 input() 函数 字符串的格式化 实验步骤 每一种编程语言都有它们自己的语法规则,就像我们所说的外语. 1. 关键字和标识符 ...

  2. io多路复用(二)

    服务端 import socket sk1 = socket.socket() sk1.bind(('127.0.0.1',8001,)) sk1.listen() inputs = [sk1,] i ...

  3. 【iOS】Swift LAZY 修饰符和 LAZY 方法

    延时加载或者说延时初始化是很常用的优化方法,在构建和生成新的对象的时候,内存分配会在运行时耗费不少时间,如果有一些对象的属性和内容非常复杂的话,这个时间更是不可忽略.另外,有些情况下我们并不会立即用到 ...

  4. poj 2142 The Balance

    The Balance http://poj.org/problem?id=2142 Time Limit: 5000MS   Memory Limit: 65536K       Descripti ...

  5. phalcon框架命名空间

    命名空间第一影像就是实际上就相当宏定义,就是需要把一个很长的带有路径的类文件指定一个空间,然后就可直接用简单简写模式 当然如果是外部文件需要首先引入外部文件,如果不引入外部文件还是会报错.一般最会出错 ...

  6. 07_Python的控制判断循环语句1(if判断,for循环...)_Python编程之路

    Python的数据类型在前几节我们都简单的一一介绍了,接下来我们就要讲到Python的控制判断循环语句 在现实编程中,我们往往要利用计算机帮我们做大量重复计算的工作,在这样的情况下,需要机器能对某个条 ...

  7. SpringBoot的配置文件加载顺序和使用方式

    1.bootstrap.properties bootstrap.properties 配置文件是由"根"上下文优先加载,程序启动之初就感知 如:Spring Cloud Conf ...

  8. GIT入门笔记(4)- GIT 安装

    关于Windows下的安装工具-msysgit Windows下要使用很多Linux/Unix的工具时,需要Cygwin这样的模拟环境,Git也一样. Cygwin的安装和配置都比较复杂,不建议直接折 ...

  9. java 数组排序方法整理,简单易懂,

    1.快速排序:首先是最简单的Array.sort,直接进行排序: public static void main(String[] args) { int[] arr = {4,3,5,1,7,9,3 ...

  10. [Leetcode] 220. Contains Duplicate III

    Given an array of integers, find out whether there are two distinct indices i and j in the array suc ...