AtCoder Beginner Contest 252
AtCoder Beginner Contest 252
D
题意
在数组中形如 \(1\leq i<j<k\leq n\)使得\(a_i,a_j,a_k\)互不相同,求共有多少组满足条件
思路
它的数据范围\(1\leq a_i\leq 2*10^5\),这就用个数组求个前缀和就搞定了。
代码
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],cnt[a[i]]++;
int ans=0;
for(int i=1;i<N;i++) sum[i]=sum[i-1]+cnt[i];
for(int i=1;i<N;i++)
{
ans+=cnt[i]*sum[i-1]*(sum[N-1]-sum[i]);
}
cout<<ans<<endl;
}
E (最短路)
题意
给个n个节点m条边的图,问把最短路弄出来后需要保留哪些边。
思路
dijkstra 求一遍,加个参数表示当前边的序号,表示在最短路中当前结点和父节点是通过该条边连接的。
这题最大的收获不是复习这个最短路,而是发现了memset不能赋值
1e18,以后还是用fill初始化吧
代码
void add(int a,int b,int c,int i)
{
e[idx]=b;
w[idx]=c;
id[idx]=i;
ne[idx]=h[a];
h[a]=idx++;
}
void dijk()
{
memset(dis,inf,sizeof(dis));
dis[1]=0;
priority_queue<pii> q;
q.push({0,1});
while(q.size())
{
pii tmp = q.top();
int u=tmp.second;
q.pop() ;
if(vis[u]) continue;
vis[u]=true;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(dis[j]>dis[u]+w[i])
{
dis[j]=dis[u]+w[i];
q.push({-dis[j],j});
use[j]=id[i];
}
}
}
}
void solve()
{
memset(h,-1,sizeof(h));
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c,i);
add(b,a,c,i);
}
dijk();
for(int i=2;i<=n;i++) cout<<use[i]<<" ";
cout<<endl;
}
F
题意
一块长为L的面包,然后有n个小朋友,每个人要吃\(A_i\)长度的面包,将一块长为x的面包切一下需要花费x,这块面包就变成x-k和k了。问最少花费多少来满足小朋友的要求,面包可以有剩下。
思路
经典枯坐半小时, 还是灰溜溜看题解
逆向思维。贪心地想,一块面包肯定是从一块长度大于它且是最短的面包中切出来的,所以这块面包应该和其他面包中最短的那个组合起来的,这样是最优解。
代码
void solve()
{
cin>>n>>m;
priority_queue<int> q;
int sum=0;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
q.push(-x);
sum+=x;
}
if(m-sum>0) q.push(sum-m);
int ans=0;
while(q.size()>1)
{
int x1=q.top();q.pop();
int x2=q.top();q.pop();
ans-=x1+x2;
q.push(x1+x2);
}
cout<<ans<<endl;
}