补题:AtCoder ABC245


C - Choose Elements

题意:给出两个长度为$n$的数组$A$和$B$和一个整数$K$,构造一个长度为$n$的数组,满足第$i$位是$A_i$或$B_i$且相邻两数绝对值差不超过$K$

解法:考虑$dp$,定义$dpa[i]$:$A$的第$i$位数字能否作为构造数组的第$i$位,能为1,否为0,同理定义$dpb[i]$,则转移方程为:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const long long mod = 1e9 + 7;
const int inf = 0x7fffffff;
const int maxn = 2e5 + 5;

int n,k,a[maxn],b[maxn];
bool dpa[maxn],dpb[maxn];
int main(){
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;++i){
cin>>a[i];
}
for(int i=1;i<=n;++i){
cin>>b[i];
}
dpa[1] = dpb[1] = true;
for(int i=1;i<=n;++i){
if(abs(a[i]-a[i-1])<=k) dpa[i] |= dpa[i-1];
if(abs(a[i]-b[i-1])<=k) dpa[i] |= dpb[i-1];
if(abs(b[i]-a[i-1])<=k) dpb[i] |= dpa[i-1];
if(abs(b[i]-b[i-1])<=k) dpb[i] |= dpb[i-1];
}
if(dpa[n]||dpb[n]) cout<<"Yes\n";
else cout<<"No\n";


return 0;
}

D - Polynomial division

题意:对于多项式乘法$A(i)*B(i)=C(i)$,给出$A(i), C(i)$的每一项系数(不为0),求$B(i)$的每一项系数

解法:模拟长除法即可

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const long long mod = 1e9 + 7;
const int inf = 0x7fffffff;
const int maxn = 2e5 + 5;

int n,m;
ll a[1005],b[1005],c[1005];

int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=0;i<=n;++i){
cin>>a[i];
}
for(int i=0;i<=m+n;++i){
cin>>c[i];
}
for(int i=m;i>=0;--i){
ll d = c[i+n]/a[n];
b[i] = d;
int cnt = n;
for(int j=i+n;j>=0;--j){
c[j] -= d * a[cnt--];
}
}
for(int i=0;i<=m;++i){
cout<<b[i]<<" ";
}
cout<<"\n";

return 0;
}

E - Wrapping Chocolate

题意:给出N个巧克力和M个盒子的长宽,每个盒子最多只能装一个巧克力,问能否将N个巧克力全部装入盒子里(能装入盒子的条件是巧克力的长$\le$盒子的长,且巧克力的宽$\le$盒子的宽)

解法:将巧克力和盒子合并在一起考虑,以宽度降序排序,宽度相同的盒子在前。开一个multiset,遍历整个序列,如果是盒子则将盒子的长加入multiset,否则在multiset中二分找到第一个不小于该巧克力长的盒子长,删去它,如果找不到,则No,如果能完成全部遍历则Yes

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const long long mod = 1e9 + 7;
const int inf = 0x7fffffff;
const int maxn = 2e5 + 5;

int n,m;
pair<int,int> ab[maxn],cd[maxn];
struct node{
int x,y,id; // 0:box; 1:chocolate
}a[maxn<<1];
bool cmp(node &x1,node &x2){
if(x1.x!=x2.x) return x1.x > x2.x;
if(x1.y!=x2.y) return x1.y > x2.y;
return x1.id < x2.id;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>ab[i].first;
for(int i=1;i<=n;++i) cin>>ab[i].second;
for(int i=1;i<=m;++i) cin>>cd[i].first;
for(int i=1;i<=m;++i) cin>>cd[i].second;

for(int i=1;i<=n;++i){
a[i].id = 1;
a[i].x = ab[i].first;
a[i].y = ab[i].second;
}
for(int i=1;i<=m;++i){
a[i+n].id = 0;
a[i+n].x = cd[i].first;
a[i+n].y = cd[i].second;
}
sort(a+1,a+1+n+m,cmp);
multiset<int> se;
for(int i=1;i<=n+m;++i){
if(a[i].id==0){
se.insert(a[i].y);
}else{
auto it = se.lower_bound(a[i].y);
if(it==se.end()) return cout<<"No\n",0;
se.erase(it);
}
}
cout<<"Yes\n";

return 0;
}

F - Endless Walk

题意:给出一个N个点M条边的有向图,问满足以下条件的节点的个数:从该点出发能够进入无限循环

解法:显然所有SCC里的点都满足要求,除此之外,所有能到达一个[节点数大于1的SCC]的节点也满足要求,因此考虑Tarjan缩点后反向建边然后从所有[节点数大于1的SCC]开始dfs即可

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const long long mod = 1e9 + 7;
const int inf = 0x7fffffff;
const int maxn = 2e5 + 5;

int n,m;

struct Edge{
int u,v,next;
}e[maxn];
std::vector<int> ee[maxn];
int gcnt,head[maxn];
inline void init_graph(){
gcnt=0;
memset(head,-1,sizeof(head));
}
inline void addedge(int u,int v){
e[gcnt]=Edge{u,v,head[u]};
head[u]=gcnt++;
}

int low[maxn],dfn[maxn],sta[maxn],color[maxn],vis[maxn],top,scc,deep;
int cnt[maxn];
void tarjan(int u){
vis[sta[++top]=u]=1;
low[u]=dfn[u]=++deep;
for(int i=head[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(low[u]==dfn[u]){
vis[u]=0;
color[u]=++scc;
while(sta[top]!=u){
color[sta[top]]=scc;
vis[sta[top--]]=0;
}
top--;
}
}

bool ma[maxn];
void dfs(int u){
for(auto &v:ee[u]){
if(!ma[v]){
ma[v] = 1;
dfs(v);
}
}
}

int main(){
init_graph();
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<=m;++i){
scanf("%d%d",&u,&v);
addedge(u,v);
}
for(int i=1;i<=n;++i){
if(!dfn[i]) tarjan(i);
}
for(int i=1;i<=n;++i) cnt[color[i]]++;

for(int u,v,i=0;i<m;++i){
u = color[e[i].u];
v = color[e[i].v];
if(u!=v){
ee[v].emplace_back(u);
}
}
for(int i=1;i<=scc;++i){
if(!ma[i] && cnt[i]>1) ma[i]=1, dfs(i);
}
int ans = 0;
for(int i=1;i<=scc;++i){
if(ma[i]) ans += cnt[i];
}
printf("%d\n",ans);

return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!