A. Two distinct points(签到)
题目链接:https://codeforces.com/contest/1108/problem/A
题目大意:在一个数轴上,有两个线段,这两条线段可能重合||相交||分离。我们从这两个线段中选择两个不重复的点,然后输出即可。
思路:就是一个直接输出的题??!!比较一下,然后输出就行了。
AC:
int main(){
int T;
while(cin>>T){
while(T--){
int a,b,c,d;
cin>>a>>b>>c>>d;
if(a!=c) cout<<a<<" "<<c<<endl;
else if(b!=d) cout<<b<<" "<<d<<endl;
else cout<<a<<" "<<b<<endl;
}
}
}
B. Divisors of Two Integers(暴力)
题目链接:https://codeforces.com/contest/1108/problem/B
题目大意:你有两个数x,y,然后是一个数组a,这个数组中包含了这两个数的所有因数,如果有相同因数的话,都要加进去。问x,y分别是什么。
思路:两个最大的数就是因数了,首先找到最大的,必定是x,然后把x的因数去除,最大的就是y了
AC:
int arr[MAXN];
int main(){
int n;
while(cin>>n){
for(int i=1;i<=n;++i){
cin>>arr[i];
}
sort(arr+1,arr+n+1);
int ansa=arr[n],ansb;
for(int i=n-1;i>=1;--i){
if(ansa%arr[i]!=0||arr[i]==arr[i+1]){
ansb=arr[i];
break;
}
}
cout<<ansa<<" "<<ansb<<endl;
}
}
C. Nice Garland(暴力)
题目链接:https://codeforces.com/contest/1108/problem/C
题目大意:三种颜色的灯泡,R,G,B,如果两个同样的灯泡之间距离正好=3,就是说(kindi=kindj&&abs(i-j)%3==0),就说这个排列时好的。问你如何改变这一个序列,使用最少的修改颜色数,让这个序列变成好序列。
思路:三种灯,排列组合有6种,我是直接对于每种排列组合直接暴力了,然后从中选出最少的那种组合。
AC:
char res[6][4]={"RGB","RBG","GRB","GBR","BGR","BRG"};
int main(){
int n;
string s="";
while(cin>>n){
cin>>s;
int ansi,ans=INF32;
for(int i=0;i<6;++i){
int e=0;
for(int j=0;j<n;++j){
if(res[i][j%3]!=s[j])
e++;
}
if(e<ans){
ansi=i;
ans=e;
}
}
cout<<ans<<endl;
for(int i=0;i<n;++i){
cout<<res[ansi][i%3];
}cout<<endl;
s="";
}
}
D. Diverse Garland(暴力)
题目链接:https://codeforces.com/contest/1108/problem/D
题目大意:C的变形,仍是三种颜色的灯。我们现在认为相邻的灯的颜色不一样就是好的序列。问原序列经过最少多少次染色后能变成好序列。
思路:直接暴力,遍历一遍,只用看后面的用不用染成其他颜色。就行了。
AC:
int main(){
int n;char s[MAXN];
while(cin>>n){
clean(s,'\0');
cin>>s;int cnt=0;
for(int i=1;i<n;++i){
if(s[i]==s[i-1]){
if(s[i]=='R'){//red
if(s[i+1]=='R') s[i]='G';
else if(s[i+1]=='G') s[i]='B';
else s[i]='G';
cnt++;
}
else if(s[i]=='G'){//green
if(s[i+1]=='R') s[i]='B';
else if(s[i+1]=='G') s[i]='B';
else s[i]='R';
cnt++;
}
else{//bule
if(s[i+1]=='R') s[i]='G';
else if(s[i+1]=='G') s[i]='R';
else s[i]='G';
cnt++;
}
}
}
cout<<cnt<<endl;
for(int i=0;i<n;++i){
cout<<s[i];
}cout<<endl;
}
}
E1. Array and Segments (Easy version)(暴力)
题目链接:https://codeforces.com/contest/1108/problem/E1
题目大意:给你一个数组,和m个区间,问你从这些区间种选择一些区间,让这些区间内的数每个-1.(每个区间都操作一次)。问最后能得出来最大的数(数组中最大的数-最小的数)是多少。并且输出所选择的区间个数和区间。
思路:简单版本的数据范围都好小,直接 for for for 就暴力掉了,把所有的认为最大值和认为最小值都选一便就行了。
AC:
int arr[MAXN],line[310][2];
int main(){
int n,m;
while(cin>>n>>m){
for(int i=1;i<=n;++i){
cin>>arr[i];
}
for(int i=1;i<=m;++i){
cin>>line[i][0]>>line[i][1];
}
int ansi,ansj,ansline,ans=-INF32;
for(int i=1;i<=n;++i){// choose a dot become the maxval dot
for(int j=1;j<=n;++j){//choose a different dot become the minval dot
int res=arr[i]-arr[j],resline=0;
for(int k=1;k<=m;++k){//check all edge,find onle reduce(contain) the minval dot's edge
if((line[k][0]>i||line[k][1]<i)&&(line[k][0]<=j&&line[k][1]>=j)){
res++;resline++;
}
}
if(res>ans){
ansi=i;ansj=j;
ans=res;ansline=resline;
}
}
}
cout<<ans<<endl<<ansline<<endl;
for(int i=1;i<=m;++i){
if((line[i][0]>ansi||line[i][1]<ansi)&&(line[i][0]<=ansj&&line[i][1]>=ansj)){
cout<<i<<" ";
}
}cout<<endl;
}
}
AC2:学习E2的题解的时候看到另一种方法,据他说是O(n(n+m))但是看着循环有点像O(n(n+nm)).....
int arr[MAXN],l[MAXN],r[MAXN],b[MAXN];
vector<int> v,ans;
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;++i){
cin>>arr[i];
}
for(int i=1;i<=m;++i){
cin>>l[i]>>r[i];
}
ll val=-INF64;
for(int i=1;i<=n;++i){
v.clear();
ll maxx=-INF64,minn=INF64;
for(int j=1;j<=n;++j){
b[j]=arr[j];// initialize arr_b
}
for(int j=1;j<=m;++j){
if(l[j]>i||r[j]<i){// this point is not in the line
v.push_back(j);//line_j can be accept
for(int k=l[j];k<=r[j];++k)//traverse all points belong the line_j
b[k]--; //val_k will be minus
}
}
for(int i=1;i<=n;++i){//traverse all points.and get the maxx,minn num
if(b[i]<minn) minn=b[i];
if(b[i]>maxx) maxx=b[i];
}
if(maxx-minn>val) ans=v;//refresh ans
val=max(val,maxx-minn);//refresh val
}
cout<<val<<endl;
cout<<ans.size()<<endl;
vector<int>::iterator it;
it=ans.begin();
for(;it!=ans.end();++it){
cout<<*it<<" ";
}cout<<endl;
}
E2. Array and Segments (Hard version)
题目链接:https://codeforces.com/contest/1108/problem/E2
题目大意:题意和E1一样,只不过数据范围变大了
思路:我们写E1的时候,用的n*n对于每个n*n找m,所以是n*n*m,现在肯定不能了,我就想,只遍历1边,找最小的那个,最大的那个用线段树来维护,每次查询的时候,直接查询最大的,然后和当前这个点相减,判断是否能够刷新ans,对于每个最小的点,遍历所有的边一次。总体来说是O(n*m*logn)的复杂度,其实我觉得这个也有点玄。。但没想到竟然过了。。
AC:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
//#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
ll tree[MAXN<<2],add[MAXN<<2];
int arr[MAXN],l[310],r[310];
vector<int> vec[MAXN];
void intt(){
clean(tree,0);clean(add,0);
clean(arr,0);clean(l,0);clean(r,0);
for(int i=0;i<MAXN;++i)
vec[i].clear();
}
void build_tree(int l,int r,int rt){
if(l==r){
tree[rt]=arr[l];
//cout<<"point "<<l<<": "<<tree[rt]<<endl;
return ;
}
int mid=(l+r)>>1;
build_tree(l,mid,rt<<1);
build_tree(mid+1,r,rt<<1|1);
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void push_down(int rt){
if(add[rt]!=0){
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
tree[rt<<1]+=add[rt];
tree[rt<<1|1]+=add[rt];
add[rt]=0;
}
}
void updata(int ql,int qr,int x,int l,int r,int rt){
if(ql<=l&&qr>=r){
tree[rt]+=x;add[rt]+=x;
return ;
}
int mid=(l+r)>>1;
push_down(rt);
if(ql<=mid) updata(ql,qr,x,l,mid,rt<<1);
if(qr>mid) updata(ql,qr,x,mid+1,r,rt<<1|1);
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
int Query(int ql,int qr,int l,int r,int rt){
if(ql<=l&&qr>=r) return tree[rt];
int mid=(l+r)>>1;
push_down(rt);
int res=-INF32;
if(ql<=mid) res=Query(ql,qr,l,mid,rt<<1);
if(qr>mid) res=Query(ql,qr,mid+1,r,rt<<1|1);
return res;
}
void Show(int l,int r,int rt){
//cout<<"l~r"<<l<<" "<<r<<endl;
if(l==r){
cout<<"point: "<<l<<": "<<tree[rt]<<endl;
return ;
}
int mid=(l+r)>>1;
Show(l,mid,rt<<1);
Show(mid+1,r,rt<<1|1);
}
int main(){
int n,m;
while(cin>>n>>m){
intt();
for(int i=1;i<=n;++i){
cin>>arr[i];
}
for(int i=1;i<=m;++i){
cin>>l[i]>>r[i];
vec[l[i]].push_back(i);
vec[r[i]+1].push_back(-i);
}
int ans=-INF32,ansi;
build_tree(1,n,1);
for(int i=1;i<=n;++i){// 对每个点都试一边最小值
int len=vec[i].size();
for(int j=0;j<len;++j){
int x=vec[i][j];
if(x>0) updata(l[x],r[x],-1,1,n,1);
else updata(l[-x],r[-x],1,1,n,1);
}
int maxx=Query(1,n,1,n,1);
int minn=Query(i,i,1,n,1);
if(maxx-minn>ans){
ans=maxx-minn;
ansi=i;
}
// Show(1,n,1);cout<<tree[1]<<endl;
// cout<<"maxx,minn,ans:"<<maxx<<" "<<minn<<" "<<ans<<endl;
// cout<<"-----"<<endl;
}
int k=0;
for(int i=1;i<=m;++i){
if(l[i]<=ansi&&r[i]>=ansi)
k++;
}
cout<<ans<<endl<<k<<endl;
for(int i=1;i<=m;++i){
if(l[i]<=ansi&&r[i]>=ansi)
cout<<i<<" ";
}cout<<endl;
}
}
/*
*/
F. MST Unification(并查集改编)
题目链接:https://codeforces.com/contest/1108/problem/F
题目大意:n个点,m条边,问你修改其中的一些边(边权+1),使得这个图的最小生成树只有一种。
思路:并查集,然后修改一下就行了,说实话我这个使看题解才看出来并查集的。。只不过题解的代码好懵逼啊,我们在并查集中加一点,就是得出所有边权都相同的边,然后从中选出,符合要求的边,其余的边(除了都不选的)就是我们要修改的边了。
AC:
const int MAXN=2e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
struct node{
int s,t,val;
}edge[MAXN];
int f[MAXN];
void intt(){
for(int i=0;i<MAXN;++i){
f[i]=i;
}
}
int cmp(node a,node b){
return a.val<b.val;
}
int Find(int x){
int pre=x,nxt=x;
while(f[x]!=x){
x=f[x];
}
while(f[pre]!=x){
nxt=f[pre];
f[pre]=x;
pre=nxt;
}
return x;
}
void mix(int x,int y){
int xx=Find(x),yy=Find(y);
f[xx]=yy;
}
int main(){
int n,m;
while(cin>>n>>m){
intt();
for(int i=1;i<=m;++i){
cin>>edge[i].s>>edge[i].t>>edge[i].val;
}
sort(edge+1,edge+1+m,cmp);
int ans=0;
for(int i=1,j=1;i<=m;i=j){
while(j<=m&&edge[i].val==edge[j].val) ++j;
int res=j-i;//at the begin assume there are (j-i) same edgeval
for(int k=i;k<j;++k){
int x=edge[k].s,y=edge[k].t;
if(Find(x)==Find(y)){//if the edge is exist,we don't choose the edge
res--;
}
}
for(int k=i;k<j;++k){
int x=edge[k].s,y=edge[k].t;
if(Find(x)!=Find(y)){//we must connect the edge
res--;
mix(x,y);
}
}
ans+=res;
}
cout<<ans<<endl;
}
}