这一场写的还算是可以,4题过的比较快,但是后面就挂机了,那个数论没搞出来有点可惜…
Problem A
题目大意&题解
有n个block,每个block都有一定数量的员工,现在要重新分成k个block,要求每个block的员工数量相同,每次可以对相邻的block进行合并,也可以拆分一个block,问最少的操作次数。
可以注意到如果总数除不尽k的话肯定是分不了的;如果可以分,对于少的block要增加,对于多的block要减少,基于这个思想,我们从第一个block模拟到最后一个block,比标准值多久减少,比标准值少就增加(相同的话直接清零)。
感觉以前CF有过类似的题。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 100005
#define LL long long
using namespace std;
int T,n,k;
LL a[maxn];
int main()
{
int Case=1;
scanf("%d",&T);
while (T--)
{
memset(a,0,sizeof(a));
scanf("%d%d",&n,&k); LL sum=0;
printf("Case #%d: ",Case++);
for (int i=0;i<n;i++)
{
scanf("%I64d",&a[i]);
sum+=a[i];
}
if (sum%k!=0)
{
printf("-1\n");
continue ;
}
sum/=k; LL last=0,ans=0;
for (int i=0;i<n;i++)
{
last+=a[i];
while (last>sum)
{
last-=sum;
ans++;
}
if (last==sum)
{
last=0;
continue;
}
else ans++;
}
//if (last) ans+=(last/sum-1);
printf("%I64d\n",ans);
}
return 0;
}
Problem B
题目大意&题解
有n个炸弹,每个炸弹都有一个爆炸半径和爆炸代价,引爆一个炸弹会把半径范围里面未爆炸的所有炸弹引爆。问引爆所有炸弹的最小代价。
注意到炸弹爆炸的传递性,想到建图后强连通缩点,由于缩点后的图是个DAG,而且我们只用引爆入度为0的点集中代价最少的那一个就行了。所以在重新建图的时候维护度数和最少代价就行了。
###代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#define LL long long
#define maxn 1005
using namespace std;
int T,n,pre[maxn],cnt,dfn[maxn],low[maxn],p,c[maxn];
int sta[maxn],h,scc[maxn],num,de[maxn],ans[maxn];
bool vis[maxn];
LL x[maxn],y[maxn],r[maxn];
struct edge
{
int u,v,next;
};
edge e[maxn*maxn*2];
void addedge(int u,int v)
{
e[cnt].u=u; e[cnt].v=v;
e[cnt].next=pre[u]; pre[u]=cnt++;
}
void solve(int i,int j)
{
LL d=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
if (d<=r[i]*r[i] ) addedge(i,j);
if (d<=r[j]*r[j] ) addedge(j,i);
}
void tarjan(int u)
{
vis[u]=1; sta[h++]=u;
dfn[u]=low[u]=p++;
for (int i=pre[u];~i;i=e[i].next)
{
int v=e[i].v;
if (!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if (vis[v]) low[u]=min(low[u],dfn[v]);
}
if (dfn[u]==low[u])
{
int v;
do
{
v=sta[--h];
scc[v]=num;
ans[num]=min(ans[num],c[v]);
vis[v]=0;
}
while (u!=v) ;
num++;
}
}
void buildmap()
{
memset(de,0,sizeof(de));
int u,v;
for (int i=0;i<cnt;i++)
{
u=e[i].u; v=e[i].v;
if (scc[u]!=scc[v]) de[scc[v]]++;
}
}
int answer()
{
int ret=0;
for (int i=0;i<num;i++) if (!de[i]) ret+=ans[i];
return ret;
}
int main()
{
int Case=1;
scanf("%d",&T);
while (T--)
{
memset(pre,-1,sizeof(pre)); cnt=0;
memset(dfn,0,sizeof(dfn)); h=0; p=1;
memset(low,0,sizeof(low));
memset(scc,0,sizeof(scc)); num=0;
memset(ans,0x3f,sizeof(ans));
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%I64d%I64d%I64d%d",&x[i],&y[i],&r[i],&c[i]);
for (int i=1;i<=n-1;i++)
for (int j=i+1;j<=n;j++) solve(i,j);
for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
buildmap();
printf("Case #%d: %d\n",Case++,answer());
}
return 0;
}
Problem C
题目大意&题解
有个老司机正在飙车,他的速度是非减的,现在警察发现了他,警察有n个记录,每个记录是他在某个整点的位置,记录的位置是依次递增的,问这个老司机经过最后面一个记录点时的最短时间。
要求最短,首先最后面一段的时间肯定是1,也就是速度值等于那一段的长,然后我们从最后面一段向前模拟,每次二分找到最大的满足条件的时间,累加进答案即可。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 100005
using namespace std;
int T,a[maxn],n;
int main()
{
int Case=1;
scanf("%d",&T);
while (T--)
{
memset(a,0,sizeof(a));
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
double spe=a[n]-a[n-1],c; int l,r,mid,ans=1;
for (int i=n-1;i>=1;i--)
{
c=(double) (a[i]-a[i-1]);
l=1; r=(int)c +1;
while (l<=r)
{
mid=(l+r)>>1;
if (c/mid>spe) l=mid+1;
else r=mid-1;
}
spe=c/l;
ans+=l;
}
printf("Case #%d: %d\n",Case++,ans);
}
return 0;
}
Problem F
题目大意&题解
给你一个字符串s,要你把\(+-*/\)这四个运算符依次放入,求结果的最大值。
这一题大胆猜想只可能是两个数相乘除一个两位数或者是一位数,前面的加法也一定是一个一位数加上另外一个剩下的数,这样贪心先算出减去的值,再算出前面加法的最大值,总和一下就好了。
这个贪心感觉挺容易想到的…只是不知道怎么证明(笑着哭)
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#define LL long long
using namespace std;
int T;
char s[25];
int main()
{
int Case=1;
scanf("%d",&T);
while (T--)
{
memset(s,0,sizeof(s));
scanf("%s",s);
int l=strlen(s);
LL cost=(s[l-3]-'0')*(s[l-2]-'0')/(s[l-1]-'0');
LL ans1=0,ans2=0,ans3=0,k;
int i=l-4; k=1;
while (i>=1)
{
ans1+=(s[i]-'0')*k;
k*=10; i--;
}
ans1+=(s[0]-'0');
i=l-5; k=1;
while (i>=0)
{
ans2+=(s[i]-'0')*k;
k*=10; i--;
}
ans2+=(s[l-4]-'0');
ans1=max(ans1,ans2);
ans3=ans1-cost;
//way 2
if (l>=6)
{
LL cost=(s[l-4]-'0')*(s[l-3]-'0')/((s[l-2]-'0')*10+s[l-1]-'0');
int i=l-5; k=1; ans1=0;
while (i>=1)
{
ans1+=(s[i]-'0')*k;
k*=10; i--;
}
ans1+=(s[0]-'0');
i=l-6; k=1; ans2=0;
while (i>=0)
{
ans2+=(s[i]-'0')*k;
k*=10; i--;
}
ans2+=(s[l-5]-'0');
ans1=max(ans1,ans2);
ans1-=cost;
ans3=max(ans3,ans1);
}
printf("Case #%d: %I64d\n",Case++,ans3);
}
return 0;
}