AtCoder Beginner Contest 218 (A~F)
A - Weather Forecast
水题
B - qwerty
水题
C - Shapes
不想写模拟,555
D - Rectangles
题意 :二位坐标轴上有\(n\)个点,问你能构造多少和坐标轴平行的矩形.
题解:暴力枚举左上和右下,用map存一下每个点是否出现。
代码:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int n;
PII pt[N];
map<PII,int> mp;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d %d",&pt[i].fi,&pt[i].se);
mp[{pt[i].fi,pt[i].se}]++;
}
ll ans=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(pt[i].fi>=pt[j].fi || pt[i].se<=pt[j].se) continue;
int x1=pt[i].fi,y1=pt[j].se,x2=pt[j].fi,y2=pt[i].se;
if(mp[{x1,y1}] && mp[{x2,y2}]) ans++;
}
}
printf("%lld\n",ans);
return 0;
}
E - Destruction
题意:\(m\)条边,\(n\)个顶点的图,每条边都有边权,删去一条边可以得到这条边边权的贡献,问你在保证图是连通的情况下,能得到的最大贡献是多少。
题解:先用最小生成树把最小的边用来保证连通,剩下的边如果大于0就记录给答案即可。
代码:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int n,m;
struct Node{
int a,b;
int val;
}edge[N];
int p[N];
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main() {
scanf("%d %d",&n,&m);
for(int i=1;i<=m;++i){
scanf("%d %d %d",&edge[i].a,&edge[i].b,&edge[i].val);
}
sort(edge+1,edge+1+m,[&](Node x,Node y){
return x.val<y.val;
});
for(int i=1;i<=n;++i) p[i]=i;
ll res=0;
vector<int> v;
ll tmp=0;
for(int i=1;i<=m;++i){
int fa=find(edge[i].a);
int fb=find(edge[i].b);
int val=edge[i].val;
if(fa!=fb){
p[fa]=fb;
res+=val;
}
else v.pb(val);
}
for(auto w:v){
if(w>0) tmp+=w;
}
printf("%lld\n",tmp);
return 0;
}
F - Blocked Roads
题意:给你一张\(n\)个点\(m\)条边的有向图,所有边权为\(1\),每次删去一条边,问从\(1\)到\(n\)的最短距离。
题解:如果每次删去一条边直接暴力跑,复杂度为\(O(M*(N+M))\),但是我们先找到一条最短距离的简单路径,容易知:这条最短路径最多有\(n-1\)条边,所以,删去这条最短路径之外的边,最短距离不发生变化,那么现在就要考虑删去最短路径的边怎么办,怎么办?暴力呗,此时的复杂度被优化到\(O(N*(N+M))\).完全满足条件。
代码:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int n,m;
vector<int> edge[N];
int dis[N];
map<PII,int> rec,mp;
int ans[N];
vector<PII> v[N];
int main() {
me(dis,-1,sizeof(dis));
scanf("%d %d",&n,&m);
for(int i=1;i<=m;++i){
int u,v;
scanf("%d %d",&u,&v);
edge[u].pb(v);
rec[{u,v}]=i;
}
queue<int> q;
q.push(1);
dis[1]=0;
vector<PII> path;
while(!q.empty()){
int u=q.front();
q.pop();
for(auto w:edge[u]){
if(dis[w]==-1){
dis[w]=dis[u]+1;
q.push(w);
v[w].pb({u,w});
}
}
}
if(dis[n]==-1){
for(int i=1;i<=m;++i) printf("-1\n");
return 0;
}
int cur=n;
while(cur!=1){
path.pb({v[cur][0].fi,v[cur][0].se});
cur=v[cur][0].fi;
}
for(int i=1;i<=m;++i) ans[i]=dis[n];
for(auto w:path){
mp[{w.fi,w.se}]=1;
for(int i=1;i<=n;++i) dis[i]=-1;
while(!q.empty()) q.pop();
q.push(1);
dis[1]=0;
while(!q.empty()){
int u=q.front();
q.pop();
for(auto w:edge[u]){
if(mp[{u,w}]==1) continue;
if(dis[w]==-1){
dis[w]=dis[u]+1;
q.push(w);
}
}
}
ans[rec[{w.fi,w.se}]]=dis[n];
mp[{w.fi,w.se}]=2;
}
for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
return 0;
}
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮