第一次打ACM赛制的题目,结果T2的题意实在难懂,罚时了很久
而且T3看出来就是Tarjan缩点的水题,还有1h的情况下也懒得学Tarjan了
难度区分还可以,最起码A掉前两题再快也没有前200
A. 百度无人车
还是比较基础的一道题,当时在家里忘记提前写读优了然后就浪费了一定的时间
虽然1A,其实还是有点慢
主要思路就是二分那个最重的车的重量,然后就是很简单的O(n)check
CODE
#include<cstdio>
using namespace std;
typedef long long LL;
const int N=20005;
LL a[N],n,p,ans,s;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
x=0; char ch=tc();
while (ch<\'0\'||ch>\'9\') ch=tc();
while (ch>=\'0\'&&ch<=\'9\') x=x*10+ch-\'0\',ch=tc();
}
inline bool check(LL x)
{
LL tot=0;
for (register LL i=1;i<=n;++i)
if (a[i]>x) tot+=(a[i]-x)*p;
return tot<=s;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register LL i;
for (read(n),i=1;i<=n;++i)
read(a[i]); read(p); read(s);
LL l=1,r=20000;
while (l<=r)
{
LL mid=(l+r)>>1;
if (check(mid)) ans=mid,r=mid-1; else l=mid+1;
}
printf("%lld",ans);
return 0;
}
B. 百度科学家(简单)
这是一道神坑题,这题意实在是......
我其实几乎所有人都认为一个元素被换下后就不能拿来做实验了
好吧,其实是可以的
所以我们要记录一下每一个位置上分别是第几号元素,然后根据题意建边
然后我们对于所有的元素都枚举一遍,优先选择它(即选择它)
然后根据建出来的边的关系跑一遍BFS,把所有选了它就必须要选的点找出来,最后统计一下花费最小的点即可
一个小贪心,正确性显然,因为如果你已经做完实验后再去选择其他的元素肯定是没有这种方案优的,而一个一个枚举则确保涵盖了所有情况
CODE
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=25;
struct edge
{
LL to,next;
}e[1005];
LL head[N],a[N],q[N],w[N],n,m,opt,x,y,z,cnt,ans=1e18,tot;
bool vis[N];
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
x=0; char ch=tc();
while (ch<\'0\'||ch>\'9\') ch=tc();
while (ch>=\'0\'&&ch<=\'9\') x=x*10+ch-\'0\',ch=tc();
}
inline void add(LL x,LL y)
{
e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;
}
inline LL min(LL a,LL b)
{
return a<b?a:b;
}
inline void BFS(LL x)
{
memset(vis,0,sizeof(vis));
q[1]=x; vis[x]=1;
LL H=0,T=1;
while (H<T)
{
LL now=q[++H];
for (register LL i=head[now];i!=-1;i=e[i].next)
if (!vis[e[i].to]) vis[e[i].to]=1,q[++T]=e[i].to;
}
}
inline LL get(void)
{
LL res=0;
for (register LL i=1;i<=tot;++i)
if (vis[i]) res+=a[i];
return res;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register LL i,j;
memset(head,-1,sizeof(head));
memset(e,-1,sizeof(e));
for (read(n),i=1;i<=n;++i)
read(a[i]),w[i]=i; read(m); tot=n;
while (m--)
{
read(opt); read(x); read(y);
if (opt) for (read(z),j=y;j<=z;++j) add(w[x],w[j]); else a[++tot]=y,w[x]=tot;
}
for (i=1;i<=tot;++i)
BFS(i),ans=min(ans,get());
printf("%lld",ans);
return 0;
}
C. 百度科学家(中等)
这道题我们就在B题的基础上分析一下
对于一张有向图来说,如果选了一个点x,那么肯定没有选择它的任意一个出度的点来的优
因此我们发现:选择所有出度为0的点中权值最小的一个
但是如何你就这么写然后帅气地交上去就可以轻松地得到一个WA
Why——这样的正确性显然啊?
因为其实图中可能并没有出度为0的点,即图中可能出现环
然后我们又可以分析出,如果在同一个环中的点,选择其中的任意一个肯定是要遍历所有的环中的点的
所以这就满足了缩点的条件,我们将所有在一个环中的点都缩成一个,缩完后的点的点权就是原来环中所有点的点权和。
然后按照上面的方法就OK了
CODE
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=1e5+5,M=1e5+5;
struct edge
{
LL to,next;
}e[M];
LL w[N],a[N],v[N],head[N],dfn[N],low[N],stack[N],chu[N],col[N],n,m,opt,x,y,z,cnt,top,tot,sum,kinds,ans=1e18;
bool vis[N];
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
x=0; char ch=tc();
while (ch<\'0\'||ch>\'9\') ch=tc();
while (ch>=\'0\'&&ch<=\'9\') x=x*10+ch-\'0\',ch=tc();
}
inline void add(LL x,LL y)
{
e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;
}
inline LL min(LL a,LL b)
{
return a<b?a:b;
}
inline void Tarjan(LL now)
{
dfn[now]=low[now]=++tot;
stack[++top]=now; vis[now]=1;
for (register LL i=head[now];i!=-1;i=e[i].next)
if (!dfn[e[i].to])
{
Tarjan(e[i].to);
low[now]=min(low[now],low[e[i].to]);
} else if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]);
if (dfn[now]==low[now])
{
col[now]=++sum; vis[now]=0;
v[sum]=a[now];
while (stack[top]!=now)
{
col[stack[top]]=sum; vis[stack[top]]=0;
v[sum]+=a[stack[top--]];
} --top;
}
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register LL i,j;
for (read(n),i=1;i<=n;++i)
read(a[i]),w[i]=i; kinds=n;
memset(head,-1,sizeof(head));
memset(e,-1,sizeof(e)); read(m);
while (m--)
{
read(opt); read(x); read(y);
if (opt==1) for (read(z),i=y;i<=z;++i) add(w[x],w[i]); else a[++kinds]=y,w[x]=kinds;
}
for (i=1;i<=kinds;++i)
if (!dfn[i]) Tarjan(i);
for (i=1;i<=kinds;++i)
for (j=head[i];j!=-1;j=e[j].next)
if (col[i]!=col[e[j].to]) ++chu[col[i]];
for (i=1;i<=sum;++i)
if (!chu[i]) ans=min(ans,v[i]);
printf("%lld",ans);
return 0;
}
D. 百度科学家(困难)
这里的话就是一个边数边大了,直接存无论是空间还是时间都要爆炸
然后我们主席树优化建边之后再跑Tarjan即可我则么会主席树这种高级的东西呢,详见dalao\'s blog