Google Kick Start 2020 Round A
Posted cryingrain
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Google Kick Start 2020 Round A相关的知识,希望对你有一定的参考价值。
Allocation
题意
N个房子出售,每个卖Ai刀,现有B刀资金,求最多买多少个。
思路
贪心,排序后从小到大买
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int a[MAX];
int main()
{
int T,cas=0;
scanf("%d",&T);
while(T--)
{
int n,b,res=0;
scanf("%d%d",&n,&b);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
for(int i=0;i<n;i++)
{
if(a[i]>b)break;
b-=a[i];
res++;
}
printf("Case #%d: %d
",++cas,res);
}
}
Plates
题意
有n摞盘子,每一摞有k个,每个盘子有一定价值,现在要选p个盘子,要求每次只能选一摞的从上到下的一部分,求如何选使得总价值最大
思路
DP,dp[i][j] 表示前i摞中共选j个可得的最大价值,转移枚举当前摞选m个(选前缀),然后由 dp[i-1][j-m] 转移而来
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=1505;
int a[MAX][MAX],pre[MAX][MAX],dp[MAX][MAX];
int main()
{
int T,cas=0;
scanf("%d",&T);
while(T--)
{
int n,p,m;
scanf("%d%d%d",&n,&m,&p);
memset(dp,0,sizeof dp);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
scanf("%d",&a[i][j]);
pre[i][j]=pre[i][j-1]+a[i][j];
}
for(int i=1; i<=n; i++)
for(int j=0; j<=min(i*m,p); j++)
for(int k=0; k<=min(j,m);k++)
dp[i][j]=max(dp[i][j],dp[i-1][j-k]+pre[i][k]);
printf("Case #%d: %d
",++cas,dp[n][p]);
}
}
Workout
题意
给一个单调递增序列,有n个数,设D值为此序列每个数与相邻数的差的最大值,现在可以在保证序列单调增的情况下,在此序列任意位置插入任意大小的k个数,求如何使得此序列D值最小,求出最小D值。
思路
容易想到,可以在两个数中间插a个数,使得两者差变为原来的a分之一(向上取整),先处理出原序列所有差,然后二分答案,再通过上述结论检测此答案是否可行,最后得到最小值。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int n,k,a[MAX],ch[MAX];
bool check(int x)
{
int tot=k;
for(int i=1; i<n; i++)
{
if(ch[i]<=x)continue;
for(int j=1;; j++)
{
int cur=(ch[i]+j)/(j+1);
if(cur<=x)
{
if(j<=tot)tot-=j;
else return 0;
break;
}
}
}
return 1;
}
int main()
{
int T,cas=0;
scanf("%d",&T);
while(T--)
{
int L=1,R=-1,res;
scanf("%d%d",&n,&k);
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
for(int i=1; i<n; i++)
ch[i]=a[i]-a[i-1],R=max(R,ch[i]);
while(L<=R)
{
int mid=(L+R)>>1;
if(check(mid))
{
res=mid;
R=mid-1;
}
else
L=mid+1;
}
printf("Case #%d: %d
",++cas,res);
}
}
Bundling
题意
给n个字符串,要求分成大小为k的若干组(n是k的倍数),每组的得分为该组所有字符串的最长公共前缀长度。求如何使得得分最大化,求出最大得分。
思路
显然公共前缀越长越好,所以贪心,找公共前缀最长的能分成一组的就分成一组,建一棵字典树,记录以某前缀开头的字符串数量。然后在字典树上贪心寻找尽可能深的,足够分成一组的前缀(即寻找以此前缀开头的字符串数量大于等于k的前缀),然后用深度更新答案,再返回已经用过的数量给父亲,更新父亲的数量。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e6+6;
typedef long long ll;
int nxt[MAX][26],sum[MAX],cnt,n,k;
ll res;
char ss[MAX];
void ins(char *s)
{
int p=0,len=strlen(s);
sum[p]++;
for (int i=0; i<len; i++)
{
int c=s[i]-‘A‘;
if(!nxt[p][c])nxt[p][c]=++cnt;
p=nxt[p][c];
sum[p]++;
}
}
int dfs(int x,int d)
{
int ssum=0,cur=0;
for(int i=0;i<26;i++)
if(nxt[x][i])
ssum+=dfs(nxt[x][i],d+1);
sum[x]-=ssum;
if(sum[x]>=k)
{
cur=sum[x]/k;
res+=d*cur;
sum[x]%=k;
}
return ssum+cur*k;
}
void init()
{
memset(nxt,0,sizeof nxt);
memset(sum,0,sizeof sum);
cnt=0;
res=0;
}
int main()
{
int T,cas=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
init();
for(int i=0;i<n;i++)
{
scanf("%s",ss);
ins(ss);
}
dfs(0,0);
printf("Case #%d: %lld
",++cas,res);
}
}
以上是关于Google Kick Start 2020 Round A的主要内容,如果未能解决你的问题,请参考以下文章
Round A 2020 - Kick Start 2020
Round G 2019 - Kick Start 2019