How to AK ABC252
__vector__ · · 个人记录
前言:
被 D 题降智,E 题写了个 kruskal 结果被卡了,F 题是个普及组难度的原题但是我没去看,最后 rating:
A
int ch=getchar();
cout<<char(ch);
两行代码结束。
复杂度:
B
这个东西直接模拟就行了。
复杂度:
#include <bits/stdc++.h>
using namespace std;
namespace Main
{
const int maxn=105;
int a[maxn],b[maxn];
int k,n;
int imax=0;
void main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
imax=max(imax,a[i]);
}
for(int i=1;i<=k;i++)
{
cin>>b[i];
if(a[b[i]]==imax)
{
printf("Yes");
return;
}
}
printf("No");
}
}
int main()
{
Main::main();
return 0;
}
C
可以枚举
算一下就可以发现,最多 1000 秒就能使所有的卷轴显示相同的数字,因为极端情况下
总复杂度:
#include <bits/stdc++.h>
using namespace std;
namespace Main
{
const int maxn=105;
char s[maxn][15];
int n;
bool vis[maxn];
void main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s[i]);
}
int ans=0x3f3f3f3f;
for(int i=0;i<10;i++)//zimu
{
int col=0;
for(int t=0;t<=1000;t++)//miaoshu
{
bool flag=1;
for(int j=1;j<=n;j++)
{
if(!vis[j])
{
if(s[j][t%10]==(i+'0'))
{
vis[j]=1;
break;
}
}
}
for(int j=1;j<=n;j++)
{
if(!vis[j])
{
flag=0;
break;
}
}
if(flag)
{
col=t;
break;
}
}
ans=min(ans,col);
for(int j=1;j<=n;j++)
{
vis[j]=0;
}
}
printf("%d",ans);
}
}
int main()
{
Main::main();
return 0;
}
D
可以先计算所有情况,然后再减去不合法情况。
假设由有
那么先定义两个函数,方便后面使用:
long long sum_3(long long n)
{
return n*(n-1)*(n-2)/6;
}
long long sum_2(long long n)
{
return n*(n-1)/2;
}
设一个元素
- 第一种情况是三元组的组成元素全都是
a_i ,这种情况有\dfrac{x \cdot (x-1) \cdot (x-2)}{6} 个,也就是sum_3(x)。 - 第二种情况是三元组的两个元素是
a_i ,直接在数组所有重复的a_i 中挑选有\dfrac{x \cdot (x-1)}{2} 个组合,显然,每个组合都会与其他n-2 个元素形成新的组合,有\dfrac{x \cdot (x-1)}{2} \cdot (n-2) 个情况。但是别忘了,其中有\dfrac{x \cdot (x-1)}{2} \cdot (x-2) 种情况会组合成三个元素都相等的三元组,而这些情况已经在第一条处理过,这里不需要再处理,所以实际上只用处理\dfrac{x \cdot (x-1)}{2} \cdot [n-2-(x-2)]=\dfrac{x \cdot (x-1)}{2} \cdot (n-x) 个情况
综上,设每个元素出现了
复杂度 unordered_map 是
#include <bits/stdc++.h>
using namespace std;
namespace Main
{
typedef long long ll;
const int maxn=2e5+5;
unordered_map<int,int> im;
int a[maxn];
int n;
ll sum_3(ll n)
{
return n*(n-1)*(n-2)/6ll;
}
ll sum_2(ll n)
{
return n*(n-1)/2ll;
}
void main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
im[a[i]]++;
}
ll ans=sum_3(n);
for(int i=1;i<=n;i++)
{
if(im[a[i]])
{
ans-=sum_3(im[a[i]]);
ans-=sum_2(im[a[i]])*ll(n-im[a[i]]);
im[a[i]]=0;
}
}
printf("%lld",ans);
}
}
int main()
{
Main::main();
return 0;
}
E
不懂 prim 的请自行百度
这道题让构造一棵树使得 prim(赛时我不会 prim,所以寄了)。
这道题算是把堆优化版 prim 板子改改就能过的那种,来说一下:
- 把更新最短路的地方改成
dijkstra的做法。 - 用
pair的第一个关键字来存储边权,第二个关键字存储边的编号。当要取出队首节点时,直接取出edge[que.top().second].to即可。 - 如果
1 点存入小根堆种,取出队首节点时不会取出1 点,而是取出1 指向的节点,所以应该建立一个0 号节点并将其连向1 节点,初始时将0 号节点压入小根堆。 - 用一个
queue<int> ans来存储每个需要的边,每弹出队首,就将这条边加入其中,也就是:int id=que.top().second; ans.push((id+1)/2);注:之所以id 要加1 然后除以2 是因为建图的时候建的双向边,编号为1,2 的是一条边,编号为3,4 的是一条边..........
这道题就结束了。
复杂度:
#include <bits/stdc++.h>
using namespace std;
namespace Main
{
typedef long long ll;
const int maxn=2e5+5;
const int maxm=2e5+5;
int head[maxn<<1];
bool vis[maxn];
ll dis[maxn];
struct EDGE
{
int to,nxt,val;
}edge[maxm<<1];
int cnt;
inline void add(int u,int to,int val)
{
edge[++cnt].to=to;
edge[cnt].val=val;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
int n,m;
inline void prim()
{
queue<int> ans;
priority_queue<pair<ll,int>> que;
for(int i=0;i<=n;i++)
{
dis[i]=1e18;
}
dis[1]=0;
que.push(make_pair(0,m*2+1));
int tot=0;
while(tot<n&&!que.empty())
{
int id=que.top().second;
int u=edge[id].to;
que.pop();
if(vis[u])continue;
vis[u]=1;
ans.push(((id+1)>>1));
tot++;
for(int i=head[u];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(dis[to]>dis[u]+ll(edge[i].val))
{
dis[to]=dis[u]+ll(edge[i].val);
que.push(make_pair(-dis[to],i));
}
}
}
ans.pop();
while(ans.size()!=0)
{
printf("%d ",ans.front());
ans.pop();
}
}
void main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int xi,yi,zi;
scanf("%d%d%d",&xi,&yi,&zi);
add(xi,yi,zi);
add(yi,xi,zi);
}
add(0,1,0);
prim();
}
}
int main()
{
Main::main();
return 0;
}
F
这道题是 合并果子 原题,相信谁都会我就不说了
大意:给定一个大小为
每次可以将一块面包切成两个任意大小的面包。每次切割面包都会产生相当于原来面包大小的代价,问完成操作的最小代价是多少。
把这个过程倒过来,变成合并面包就行了。现在问题转化为有
显然,每次选出大小最小的两个面包合并就能保证最后代价最小,用小根堆维护即可。
复杂度:
#include <bits/stdc++.h>
using namespace std;
namespace Main
{
typedef long long ll;
const int maxn=2e5+5;
ll a[maxn];
priority_queue<ll> que;
int n;
ll l;
void main()
{
scanf("%d%lld",&n,&l);
ll ans=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
que.push(-a[i]);
l-=ll(a[i]);
}
if(l>0)
{
que.push(-l);
}
n=que.size();
for(int i=1;i<n;i++)
{
ll t1=-que.top();
que.pop();
ll t2=-que.top();
que.pop();
ans+=t1+t2;
que.push(-t1-t2);
}
printf("%lld",ans);
}
}
int main()
{
Main::main();
return 0;
}
Ex
题目简略翻译:
有
有
现在要在
问价值为第
题目分析:
老子不会
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
cout<<"老子不会";
return WA;
}