A.Three Pairwise Maximums
首先最大的在原序列中肯定出现至少两次否则不能构造,即min max max
,对于答案min min max
肯定满足题意
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int main()
{IO;int T;cin>>T;while(T--){int x,y,z;cin>>x>>y>>z;if(x>y) swap(x,y);if(y>z) swap(y,z);if(x>y) swap(x,y);if(z!=y) cout<<"NO"<<endl;else {cout<<"YES"<<endl;cout<<x<<" "<<x<<" "<<y<<endl;}}return 0;
}
B. Restore the Permutation by Merger
第二题直接开个map记录一下就行了。最气的是wa了一次(数组开小了我🤮了)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=60;//最开始N=50 wa了一次,这种低级错误我🤮了
int mp[N],n;
int main()
{IO;int T;cin>>T;while(T--){memset(mp,0,sizeof mp);cin>>n;for(int i=1;i<=2*n;i++){int a;cin>>a;if(mp[a]) continue;mp[a]=1;cout<<a<<" ";}cout<<endl;}return 0;
}
C. Make It Good
这题就是从后往前找^
就行了。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=200010;
int a[N],n;
int main()
{IO;int T;cin>>T;while(T--){cin>>n;for(int i=1;i<=n;i++) cin>>a[i];int i=n;for(;i;i--)if(a[i]>a[i-1]) break;int j=i;for(;j;j--) if(a[j]<a[j-1]) break;if(j==0) cout<<j<<endl;else cout<<j-1<<endl;}return 0;
}
D. a-Good String
看数据范围,对于216=655362^{16}=65536216=65536所以直接暴力就行了,分而治之。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
const int N=200010;
int n;
string s;
int res=0x3f3f3f3f;
void dfs(int l,int r,int x,int ans)
{if(ans>=res) return;if(r==l){if(s[l]!=char('a'+x)) ans++;res=min(res,ans);}int mid=l+r>>1;int cnt1=0,cnt2=0;for(int i=l;i<=mid;i++)if(s[i]!=char('a'+x)) cnt1++;dfs(mid+1,r,x+1,ans+cnt1);for(int i=mid+1;i<=r;i++)if(s[i]!=char('a'+x)) cnt2++;dfs(l,mid,x+1,ans+cnt2);
}
int main()
{IO;int T;cin>>T;while(T--){cin>>n;cin>>s;res=0x3f3f3f3f;dfs(0,n-1,0,0);cout<<res<<endl;}return 0;
}
做了上面四个题,比之前多做一题。-。-还是太菜
E.Directing Edges
昨天晚上打完比赛后,躺在床上就想这个题,突然灵光一现,发现只需要搞个拓扑排序就行了。今天早上起晚了,醒了就赶快写了一下发现漂亮的AC
了。
先不考虑无向边,对有向边进行拓扑排序,如果有向边不是拓扑序那么答案肯定是YES
否则答案肯定是NO
,对于不考虑无向边的拓扑序肯定是一些拓扑序,只要对无向边从拓扑序前面向拓扑序后面连边,肯定不会出现环。对于两个独立的拓扑序,也可以按照上述方式连边。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef pair<int,int> pii;
const int N=200010,M=400010;
int n,m;
int h1[N],h2[N],e[M],ne[M],idx;
bool st[N];
int cnt;
vector<pii> res;
void add(int h[],int a,int b)
{e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
int q[N],d[N];
bool top_sort()
{int tt=-1,hh=0;for(int i=1;i<=n;i++)if(!d[i]) q[++tt]=i;while(tt>=hh){int t=q[hh++];st[t]=1;for(int i=h2[t];i!=-1;i=ne[i]){int j=e[i];if(st[j]) continue;res.push_back({t,j});}for(int i=h1[t];i!=-1;i=ne[i]){int j=e[i];if(!(--d[j])) q[++tt]=j;}}return tt==n-1;
}
int main()
{IO;int T;cin>>T;while(T--){memset(h1,-1,sizeof h1);memset(h2,-1,sizeof h2);memset(st,0,sizeof st);memset(d,0,sizeof d);idx=0,cnt=0;res.clear();cin>>n>>m;for(int i=0;i<m;i++) {int t,x,y;cin>>t>>x>>y;if(t) {res.push_back({x,y});add(h1,x,y);d[y]++;}else {add(h2,x,y);add(h2,y,x);}}if(!top_sort()) cout<<"NO"<<endl;else{cout<<"YES"<<endl;for(auto t:res) cout<<t.first<<" "<<t.second<<endl;}}return 0;
}
之前每次都是补五题,不过这次的五题可以算是自己独立做出来的(虽然E)所以有时间可以把F、G看看题解更新一下。要加油哦~
F - Removing Leaves
①维护leaf[i]
表示与第i
个节点相邻叶子(度数为1)的数量
②维护s[i]
表示与第i
个节点相邻并且不是叶子节点的编号(用STL中的set
记录
③优先队列维护leaf[]
,按照每个节点的叶子数量排序(叶子节点多的优先级高)
每次取出对头,只要能一次删除k
个就删除并统计答案同时更新每个点的度数和相邻叶子数量,倘若一个点t
的leaf[t]==0&&d[t]==1
说明该点在删除自己之前的叶子节点后自己变成了叶子节点,那么要更新s[t]
中节点的叶子数量(这时候s[t]
中有且只有一个节点v
),t
已经成了叶节点所以需要s[v].erase(t)
,然后加入队列循环此过程。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<queue>
using namespace std;
const int N=200010,M=400010;
int h[N],e[M],ne[M],idx,d[N];
int n,m;
int leaf[N];//每个点相邻叶子节点的数量
set<int> s[N];//每个点相邻不是叶子节点
struct node
{int id,cnt;bool operator < (const node &o) const{return cnt<o.cnt;}
};
priority_queue<node> heap;
void add(int a,int b)
{e[idx]=b;ne[idx]=h[a];h[a]=idx++;d[b]++;
}
void init()
{for(int i=0;i<=n;i++){s[i].clear();h[i]=-1;d[i]=0;leaf[i]=0;}while(heap.size()) heap.pop();idx=0;
}
void dfs(int u,int fa)
{for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(j==fa) continue; //由于边是双向的,需要双向加!!!//d[]>1说明不是叶子节点 d[]==1说明是叶子节点if(d[j]>1) s[u].insert(j); if(d[u]>1) s[j].insert(u);if(d[j]==1) leaf[u]++;if(d[u]==1) leaf[j]++;dfs(j,u);}
}
int main()
{IO;memset(h,-1,sizeof h);int T;cin>>T;while(T--){init();cin>>n>>m;for(int i=1;i<n;i++){int a,b;cin>>a>>b;add(a,b),add(b,a);}if(m==1){cout<<n-1<<endl;continue;}dfs(1,-1);for(int i=1;i<=n;i++)if(leaf[i]>=m) heap.push({i,leaf[i]});int res=0;while(heap.size()){if(heap.top().cnt!=leaf[heap.top().id]) {heap.pop();continue;}int t=heap.top().id;heap.pop();if(leaf[t]<m) break;else {res+=leaf[t]/m;d[t]-=leaf[t]/m*m;leaf[t]%=m;if(leaf[t]==0&&d[t]==1){int v=*s[t].begin();leaf[v]++;s[v].erase(t);if(leaf[v]>=m) heap.push({v,leaf[v]});}}}cout<<res<<endl;}return 0;
}