Codeforces Round #656 (Div. 3)
比赛链接:https://codeforces.com/contest/1385
A. Three Pairwise Maximums
题解
对
a
a
a,
b
b
b,
c
c
c进行排序。
当最大值不等于次大值表示不可能,因为肯定有一个最大数会出现两次。
否则的话输出一种构造方案即可:
最小值,最小值,最大值
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
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;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 1e5+7;
int a[N];
void solve(){
rp(i,0,2) a[i]=read();
sort(a,a+3);
if(a[2]!=a[1]) pN;
else{
pY;
cout<<a[2]<<" "<<a[0]<<" "<<a[0]<<endl;
}
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
int T=read();
while(T--) solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
B. Restore the Permutation by Merger
题解
当一个数第一次出现时,直接放进排列后面即可。
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
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;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 1e5+7;
int a[N],vis[N];
void solve(){
int n=read();
rp(i,1,2*n) a[i]=read();
rp(i,1,n) vis[i]=0;
vector<int> v;
rp(i,1,2*n){
if(!vis[a[i]]){
v.push_back(a[i]);
vis[a[i]]=1;
}
}
rp(i,0,n-1) cout<<v[i]<<(i==n-1?"\n":" ");
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
int T=read();
while(T--) solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
C. Make It Good
题解
我的做法:
容易知道当删除前缀
[
1
,
l
+
1
]
[1,l+1]
[1,l+1]满足条件的话, 那么删除前缀
[
1
,
l
]
[1,l]
[1,l]也满足,即满足可二分性,即大区间符合,小区间也符合的条件。
因此我们直接二分枚举删除的前缀长度,在判断剩下的部分是否符合条件即可。
题解做法:
根据上面的结论,我们可以直接逆序维护满足先增再减的最长区间即可。
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
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;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[N],n;
int check(int num){
int ff=1;
rp(i,num+2,n){
if(a[i-1]>a[i]) ff=0;
if(!ff&&a[i-1]<a[i]) return 0;
}
return 1;
}
void solve(){
n=read();
rp(i,1,n) a[i]=read();
int l=0,r=n;
int ans;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<<ans<<endl;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
int T=read();
while(T--) solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
D. a-Good String
题解
题目给的字符串长度很有意思,刚好是
2
17
2^{17}
217,最多需要分为
18
18
18层,因此可以直接
d
f
s
dfs
dfs暴力就行了。
时间复杂度:
O
(
n
∗
l
o
g
n
)
O(n*logn)
O(n∗logn)
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
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;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[N],n;
int check(int num){
int ff=1;
rp(i,num+2,n){
if(a[i-1]>a[i]) ff=0;
if(!ff&&a[i-1]<a[i]) return 0;
}
return 1;
}
void solve(){
n=read();
rp(i,1,n) a[i]=read();
int l=0,r=n;
int ans;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<<ans<<endl;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
int T=read();
while(T--) solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
E. Directing Edges
题解
先说结论,先按照有向边进行建图(是有向无环图DAG),
然后进行拓扑排序,求出每个点的拓扑序,
对于无向边,我们按照拓扑序从小到大建边即可构造出符合条件的图。
原因:
因为拓扑序的意义是保证排在前面的节点和排在后面的节点没有关系(即无环)。
如果最一开始用有向边建的图有环,那么构造不出来符合条件的建边方式(有向边已经成环,无法删除掉)。
代码
#include<bits/stdc++.h>
using namespace std;
#define MAXN (200000+10)
#define MAXM (200000+10)
int n,m,m1,m2,indegree[MAXN]={0},head[MAXN],nxt[MAXM]={0},edge[MAXM]={0},tot=0;
void addedge(int u,int v)
{
edge[++tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
int q[MAXN*2];
bool b[MAXN]={0};
void topsort(){
int head_=1,tail=0;
for (int i=1;i<=n;i++)
if (indegree[i]==0)
q[++tail]=i,b[i]=1;
while (head_<=tail){
int now=q[head_];
int p=head[now];
while (p){
int v=edge[p];
indegree[v]--;
if (indegree[v]==0) q[++tail]=v;b[v]=1;
p=nxt[p];
}
head_++;
}
}
int h[MAXN];
void init(){
memset(head,0,sizeof head);tot=0;
memset(indegree,0,sizeof indegree);
memset(b,0,sizeof b);
}
void solve(){
scanf("%d%d",&n,&m);
init();
vector<pair<int,int> > v1,v2,ans;
for(int i=1;i<=m;i++){
int w,u,v;scanf("%d%d%d",&w,&u,&v);
if(w){
addedge(u,v);
indegree[v]++;
v1.push_back(make_pair(u,v));
}
else v2.push_back(make_pair(u,v));
}
m2=v2.size();
m1=v1.size();
topsort();
// for(int i=1;i<=n;i++){
// cout<<i<<" "<<indegree[i]<<endl;
// }
for(int i=1;i<=n;i++){
if(indegree[i]>=1){
puts("NO");
return ;
}
}
for (int i=1;i<=n;i++) h[q[i]]=i;
for(int i=0;i<m1;i++){
int u=v1[i].first,v=v1[i].second;
ans.push_back(make_pair(u,v));
}
for (int i=0;i<m2;i++){
int u=v2[i].first,v=v2[i].second;
if (h[u]<h[v]) ans.push_back(make_pair(u,v));
else ans.push_back(make_pair(v,u));
}
// for(auto val:ans) cout<<val.first<<" "<<val.second<<endl;
puts("YES");
// cout<<m1<<" "<<m2<<endl;
for(auto val:ans) cout<<val.first<<" "<<val.second<<endl;
}
int main()
{
int T;scanf("%d",&T);
while(T--) solve();
return 0;
}
F. Removing Leaves
题解
拓扑排序+模拟题,
用队列维护叶子节点大于等于
k
k
k的所有点,以及用数组记录当前点的叶子节点的个数
然后模拟删除
k
k
k个叶子节点的情况,
当删除后还有
k
k
k个叶子节点时继续加入队列里面,
当删除后自身节点变成了叶子节点,更新数组,如果与其相连的节点更新后的叶子节点个数大于等于
k
k
k,则加入队列里面。
trick:注意特判
k
=
1
k=1
k=1的情况,因为会算重复。
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
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;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int degree[N];
queue<int> q;
vector<int> G[N];
int cnt[N],inque[N];
int n,k;
void init(){
rp(i,1,n) G[i].clear();
rp(i,1,n) degree[i]=cnt[i]=inque[i]=0;
while(!q.empty()) q.pop();
}
void solve(){
n=read(),k=read();
init();
rp(i,1,n-1){
int x=read(),y=read();
degree[x]++,degree[y]++;
G[x].push_back(y);
G[y].push_back(x);
}
if(k==1){
cout<<n-1<<endl;
return ;
}
rp(i,1,n) if(degree[i]==1) cnt[G[i][0]]++;
rp(i,1,n) if(cnt[i]>=k) q.push(i),inque[i]=1;
int ans=0;
while(!q.empty()){
int t=q.front();q.pop();
ans++;
cnt[t]-=k;
degree[t]-=k;
inque[t]=0;
if(cnt[t]>=k){
q.push(t);
inque[t]=1;
}
if(degree[t]==1){
degree[t]=0;
for(auto v:G[t]){
if(degree[v]){
cnt[v]++;
if(cnt[v]>=k&&!inque[v]){
q.push(v);
inque[v]=1;
}
}
}
}
}
cout<<ans<<endl;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
int T=read();
while(T--) solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}