1223D Sequence Sorting
传送门
题意:给定一个序列,每次可以将一种数字全部移到序列开头或者末尾,询问最少要多少次可以将序列变成递增序列。
显然次数最多就是数字的种数,那么我们只需要去找那些没必要移动的数,然后用种数减去这些没必要移动的数字的种数即可。
接下来就是怎么找了:
先离散化,没必要移动的数字一定是彼此之间形成了连续的递增序列,比如:
1 1 x x 2 2 3 3 4 y 5,其中12345构成连续的递增序列,我们只需要把x和y移到前面或者后面即可,那么我们记录每个数字的第一次和最后一次出现的位置然后去找最长的满足要求的序列长度就好。
(如果懒得离散化,只需要找子序列长度的时候从1~n遍历即可
#include<bits/stdc++.h>
using namespace std;
#define maxn 300005
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int a[maxn],b[maxn],l[maxn],r[maxn];
int main(){
IOS
int t;
cin>>t;
while(t--) {
int n;
cin>>n;
for (int i = 1; i <=n ; ++i) {
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
int cnt=unique(b+1,b+n+1)-b-1;
for (int i = 1; i <=n ; ++i) {
a[i]=lower_bound(b+1,b+1+cnt,a[i])-b;
if(!l[a[i]])l[a[i]]=i;
r[a[i]]=i;
}
int pos=0,len=0,ans=0;
for (int i = 1; i <=cnt ; ++i) {
if(pos<l[i]) len++;
else len=1;
ans=max(ans,len);
pos=r[i];
l[i]=0;
}
cout<<cnt-ans<<endl;
}
return 0;
}
1277D Let’s Play the Words?
传送门
题意:给出n个二进制数的字符串,询问需要反转哪些字符串可以使所有字符串可以形成符合下面条件的排列:
- 不存在相同的字符串
- 对相邻的两个字符串,较前的字符串末尾数字与另一个字符串的开头数字一致。
如果不可能,输出-1
不难发现反转的字符串一定是0xxx1或者1xxxx0,因为如果有00或者11的匹配,我们可以把0xxx0或1xxx1插入,此时不难发现,如果只有0xxx0和1xxx1是肯定不能形成上述排列的。之后考虑存在0xxxx1和1xxx0的情况,一个简单粗暴的方法就是全部按照0xxx11xxx0或者1xxx00xxx1的方法排列,那么需要反转的字符串就是两种字符串中较多的一方,只需要开个map找合法的反转方案即可,如果没有就输出-1。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 200005
#define db double
int check(string s){
int len=s.size();
if(s[0]=='0'&&s[len-1]=='0')return 0;
else if(s[0]=='0'&&s[len-1]=='1')return 1;
else if(s[0]=='1'&&s[len-1]=='0')return 2;
else return 3;
}
vector<int> g[5],ans;
map<string,int> mp;
vector<string> st;
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int main(){
int t;
cin>>t;
while(t--){
ans.clear();
mp.clear();
int n;
cin>>n;
string s;
for (int j = 0; j <4 ; ++j) {
g[j].clear();
}
st.clear();
for (int i = 1; i <=n ; ++i) {
cin>>s;
st.push_back(s);
g[check(s)].push_back(i);
mp[s]=1;
}
int zz=g[0].size(),zo=g[1].size(),oz=g[2].size(),oo=g[3].size();
if(zo==0&&oz==0){
if(zz!=0&&oo!=0)cout<<-1<<endl;
else{
cout<<"0
"<<endl;
}
}else{
if(zo==oz)cout<<"0
"<<endl;
else{
if(zo>oz){
zo-=oz;
zo/=2;
int cnt=0;
ans.push_back(zo);
for (int i = 0; cnt<zo&&i<g[1].size() ; ++i) {
string cut=st[g[1][i]-1];
s=cut;
reverse(s.begin(),s.end());
if(mp[s]==0){
ans.push_back(g[1][i]);
cnt++;
mp[s]=1;
mp[cut]=0;
}
}
if(cnt==zo){
cout<<ans[0]<<endl;
for(int i=1;i<ans.size();i++)cout<<ans[i]<<" ";
}else{
cout<<-1;
}
cout<<"
";
}else{
swap(zo,oz);
zo-=oz;
int cnt=0;
zo/=2;
ans.push_back(zo);
for (int i = 0; cnt<zo&&i<g[2].size() ; ++i) {
string cut=st[g[2][i]-1];
s=cut;
reverse(s.begin(),s.end());
if(mp[s]==0){
ans.push_back(g[2][i]);
cnt++;
mp[s]=1;
mp[cut]=0;
}
}
if(cnt==zo){
cout<<ans[0]<<endl;
for(int i=1;i<ans.size();i++)cout<<ans[i]<<" ";
}else{
cout<<-1;
}
cout<<"
";
}
}
}
}
return 0;
}
1133F1 Spanning Tree with Maximum Degree
传送门
题意:在连通图里找一棵生成树,使得所有结点中最大度尽可能大。
直接找度最大的点,然后用kruscal的思路求就行了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 200005
#define db double
int f[maxn];
int findfa(int x){
if(f[x]==x)return f[x];
else f[x]=findfa(f[x]);
return f[x];
}
int mergefa(int a,int b){
int fa=findfa(a),fb=findfa(b);
if(fa==fb)return 0;
else{
f[fa]=fb;
return 1;
}
}
struct edge{
int u,v;
}e[maxn];
int de[maxn];
vector<int>g[maxn];
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int main(){
IOS
int n,m;
cin>>n>>m;
int ma=-1,pos=0;
for (int j = 1; j <=n ; ++j) {
f[j]=j;
}
for (int i = 0; i <m ; ++i) {
cin>>e[i].u>>e[i].v;
de[e[i].u]++;
de[e[i].v]++;
if(de[e[i].u]>ma){
ma=de[e[i].u];
pos=e[i].u;
}
if(de[e[i].v]>ma){
ma=de[e[i].v];
pos=e[i].v;
}
g[e[i].u].push_back(e[i].v);
g[e[i].v].push_back(e[i].u);
}
for(auto i:g[pos]){
cout<<pos<<" "<<i<<endl;
mergefa(pos,i);
}
for (int k = 0; k <m ; ++k) {
int u=e[k].u,v=e[k].v;
if(mergefa(u,v)){
cout<<u<<" "<<v<<endl;
}
}
return 0;
}