这场A一发7mins,Bwa2发20mins,C卡题了一会换题,D题5-7mins,E题40mins,F题假算法。
一开始A题5mins写完交的时候输出格式错了再读题耽误了2mins,B题写完13mins之后少考虑了两种情况,各RE了两发,20minsac,送了20+7分钟的罚时,C题没有细想跳开了,D题秒了,E2用的线段树T了,没有优化,F题没有耐心读。
总结:
- 读题需要读输出格式
- B题遇到有的出题人会在那种情况出fst点,总结下来就是枚举因子需要考虑因子相同的情况。
- C题可以用next_permutation写就不麻烦了。
- 开E2这种蹭时间线边缘的题时,要先开其他题。
- F题证明了自己对最小生成树俩个算法理解不够深。
题解:
A.
题意:给你两个区间让你O1输出两个数,使得这两个数都在任意个区间里,且第一个数在第一个区间里,第二个数在第二个区间里。
思路:取左端点最小的点,和未被取的最右边的点。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int main(){
//IO;
int q;cin>>q;
while(q--){
int l,r,l2,r2;cin>>l>>r>>l2>>r2;
bool ok = 0;
if(l<l2)swap(l,l2),swap(r,r2),ok=1;
if(ok)cout<<l2<<' '<<r<<'
';
else cout << r<<' '<<l2<<'
';
}
return 0;
}
B.
题意:给出两个数的所有因子,输出这两个数。
思路:取最大的因子为数1,用multiset删除掉所有数1的因子,输出剩下最大的因子。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int main(){
//IO;
int n;cin>>n;
multiset<int>s;
forn(i,n){
int x;cin>>x;
s.insert(x);
}
//cerr<<"!@"<<'
';
int b = *s.rbegin();
int m = sqrt(b);
for(int i = 1;i<=m;i++)if(b%i==0){
s.erase(s.find(i));
if(i*i!=b)s.erase(s.find(b/i));
}
cout << *s.rbegin() <<' '<<b<<'
';
return 0;
}
C.
题意:长1e5的字符串每个字符只会是RBG,求最少修改字符使得相同字符的位之差都为3。
思路:6个排列枚举出最小的,然后循环输出。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
string a[6]={"RGB","RBG","BGR","BRG","GRB","GBR"};
int main(){
IO;
int n;cin>>n;
string s;cin>>s;
int ans = inf,pos = 6;
string t="BGR",res;
do{
//cerr<<t<<'
';
int cnt = 0;
forn(i,n) if(s[i]!=t[i%3]) cnt++;
if(ans>cnt) ans = cnt,res = t;
}while(next_permutation(t.begin(),t.end()));
cout << ans <<'
';
forn(i,n) cout<<res[i%3];
return 0;
}
D.
题意:长1e5的字符串每个字符只会是RBG,求最少修改字符使得相邻位没有相同字符。
思路:贪心按顺序修改相同的第二个字符。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int a[]={'R','G','B'};
int main(){
//IO;
int n;cin>>n;
string s;cin>>s;
int ans = 0;
for1(i,n-1){
if(s[i]==s[i-1]){
ans++;
if(i+1<n&&s[i]=='R'&&s[i+1]=='B') s[i] = 'G';
else if(i+1<n&&s[i]=='B'&&s[i+1]=='R') s[i] = 'G';
else if(i+1<n&&s[i]=='G'&&s[i+1]=='B') s[i] = 'R';
else if(i+1<n&&s[i]=='B'&&s[i+1]=='G') s[i] = 'R';
else if(i+1<n&&s[i]=='R'&&s[i+1]=='G') s[i] = 'B';
else if(i+1<n&&s[i]=='G'&&s[i+1]=='R') s[i] = 'B';
else if(s[i]=='R') s[i] = 'B';
else if(s[i]=='B') s[i] = 'R';
else s[i] = 'R';
}
}
cout << ans<<'
';
cout <<s<<'
';
return 0;
}
E.
题意:1e5个数,300个区间操作,每次操作可以使这个区间所有值-1。每个操作可选可不选,问如何选择使得最终区间最大值-最小值最大。
思路:很容易想到枚举1e5个数为最大值,暴力用线段树区间修改非此点的区间,但是卡常了。可以这样优化。先将所有区间操作完,从1-n枚举每个最大值的点,如果有区间的左端点等于当前枚举的点,让该区间+1,如果有区间的右端点等于上一个枚举的点,让该区间-1。如此只用修改2m个区间。复杂度Omlogn,貌似不用线段树Omn也可以。当然建树需要O(nlogn)读入需要O(n),所以总复杂度O(n*logn)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e5+5;
int a[maxn];
class segment_tree{
public:
#define nd node[now]
#define ndl node[now<<1]
#define ndr node[now<<1|1]
struct segment_node{
int l,r,v,flag;
void update(int x){
flag += x,v += x;
}
}node[maxn<<2];
void pushup(int now){
nd.v = min(ndl.v,ndr.v);
}
void pushdown(int now){
if(nd.flag!=0){
ndl.update(nd.flag);
ndr.update(nd.flag);
nd.flag = 0;
}
}
void build(int l,int r,int now=1){
nd={l,r,0,0};
if(l==r){
nd.v = a[l];
return;
}
build(l,l+r>>1,now<<1);
build((l+r>>1)+1,r,now<<1|1);
pushup(now);
}
void update(int l,int r,int v,int now=1){
if(l<=nd.l&&r>=nd.r){
nd.update(v);
return;
}
pushdown(now);
if(l<=ndl.r)update(l,r,v,now<<1);
if(r>=ndr.l)update(l,r,v,now<<1|1);
pushup(now);
}
}tree;
int main(){
IO;
int n,m;cin>>n>>m;
for1(i,n) cin>>a[i];vector<pair<int,int> >b(m);
tree.build(1,n);
vector<int>l[n+1],r[n+1];
forn(i,m){
cin>>b[i].first>>b[i].second;
tree.update(b[i].first,b[i].second,-1);
l[b[i].first].push_back(b[i].second);
r[b[i].second].push_back(b[i].first);
}
int ans = -inf,pos = 0;
for1(i,n){
for(auto x:l[i]) tree.update(i,x,1);
for(auto x:r[i-1]) tree.update(x,i-1,-1);
//for1(j,n<<2) cerr<<tree.node[j].v<<' ';
//cerr<<'
';
if(ans<a[i]-tree.node[1].v) ans = a[i]-tree.node[1].v,pos = i;
}
cout << ans <<'
';
vector<int>res;
forn(j,m)if(pos<b[j].first||pos>b[j].second) res.push_back(j+1);
cout<<res.size()<<'
';
if(res.empty())cout<<'
';
for(auto x:res) cout<<x<<' ';
return 0;
}
F.
题意:n个点m条有边权的边的无向图。每次修改可以使得可以使一条边的边权+1,求最少修改多少次使得最小生成树唯一。
思路:不能用Prim,用Kruskal把权值相同的边所连的点未联通时先存起来,然后处理,如果此时有点边所连的点联通了,代表此边多余,ans++。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int maxn = 2e5+5;
map<int,vector<pair<int,int> > >e;
int par[maxn],rankk[maxn];int n,m;
void init(){
for1(i,n) par[i] = i,rankk[i] = 0;
}
int find(int x){
return x==par[x]?x:par[x] = find(par[x]);
}
void unit(int x,int y){
x = find(x),y = find(y);
if(x==y)return;
if(rankk[x]<rankk[y]) swap(x,y);
else if(rankk[x]==rankk[y]) rankk[x]++;
par[y] = x;
}
int main(){
IO;
cin>>n>>m;
forn(i,m){
int x,y,z;cin>>x>>y>>z;
e[z].push_back({x,y});
}
init();
int ans = 0;
for(auto x:e){
vector<pair<int,int> >a;
for(auto u:x.second){
// cerr<<"@!#!@##!@"<<'
';
if(find(u.first)!=find(u.second)) a.push_back(u);
}
for(auto u:a){
//cerr<<u.first<<' '<<u.second<<'
';
if(find(u.first)!=find(u.second)) unit(u.first,u.second);
else ans++;
}
}
cout << ans <<'
';
return 0;
}