最近比赛状态有点迷,这场题目其实都挺简单的.压根没涉及到高级的算法和思维.
A-黑白边
最小生成树裸题.判断一下无解就好了.
代码:
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int nxt[N],head[N],to[N],edge[N],ct;
void addedge(int x,int y,int z){
nxt[++ct] = head[x];head[x] = ct;to[ct] = y;edge[ct] = z;
}
struct E{
int x,y,z;
};
bool cmp(E a,E b){
return a.z < b.z;
}
vector<E> e;
int fa[N];
int find(int x){
int r,j,k;r=j=k=x;
while(r!=fa[r]) r=fa[r];
while(j!=r) j=fa[k],fa[k]=r,k=j;
return r;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
fir(i,1,n) fa[i] = i;
fir(i,1,m){
int x,y,z;
cin >> x >> y >> z;
addedge(x,y,z);
addedge(y,x,z);
E ee = {
x,y,z};
e.pb(ee);
}
sort(ALL(e),cmp);
int num = 0;
for(auto x:e){
int fx = find(x.x),fy = find(x.y);
if(fx!=fy){
num+=x.z;
fa[fx] = fy;
}
}
int f = 0;
fir(i,1,n){
int fx = find(i);
if(!f) f = fx;
else if(f!=fx){
f = -1;
break;
}
}
if(f == -1) cout << -1 << "\n";
else cout << num << '\n';
return 0;
}
B-最好的宝石
线段树裸题,比赛的时候因为一个小问题线段树的代码出错了(标注在代码里了),搞的去思路混乱,敲了个带修主席树还炸了空间…迷迷迷.
代码:
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 3e6+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
namespace seg{
int mx[N],num[N];
#define ls 2*i
#define rs 2*i+1
void add(int i,int l,int r,int p,int v){
if(l == r){
mx[i] = v,num[i] = 1;
return;
}
int mid = l + r >> 1;
if(p <= mid) add(ls,l,mid,p,v);
else add(rs,mid+1,r,p,v);
num[i] = 0;mx[i] = max(mx[ls],mx[rs]);
if(mx[ls] == mx[i]) num[i] += num[ls];
if(mx[rs] == mx[i]) num[i] += num[rs];
return;
}
//pii lmx,rmx; // 千万不要把变量设在全局上,因为在询问右半区间的时候会改掉这个值
// 这个错误以前似乎犯过一次,没想到还会再犯..和这题一血擦肩而过
pii ask(int i,int l,int r,int L,int R){
if(l >= L && r <= R) return mpr(mx[i],num[i]);
int mid = l + r >> 1;
if(R <= mid) return ask(ls,l,mid,L,R);
if(L > mid) return ask(rs,mid+1,r,L,R);
pii lmx = ask(ls,l,mid,L,mid),rmx = ask(rs,mid+1,r,mid+1,R);
pii res = mpr(max(lmx.ft,rmx.ft),0);
if(res.ft == lmx.ft) res.sd+=lmx.sd;
if(res.ft == rmx.ft) res.sd+=rmx.sd;
return res;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
fir(i,1,n){
int x;
cin >> x;
seg::add(1,1,n,i,x);
}
fir(i,1,m){
string op;int l,r;
cin >> op >> l >> r;
if(op[0] == 'C') seg::add(1,1,n,l,r);
else cout << seg::ask(1,1,n,l,r).ft << " " << seg::ask(1,1,n,l,r).sd << "\n";
}
return 0;
}
C-滑板上楼梯
贪心的先走3再走1就好了.
代码:
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
LL n;
cin >> n;
LL num = n/4;
n %= 4;
if(n == 3) cout << num*2+1;
else cout << num*2+n;
return 0;
}
D-GCD
唯一 一个和思维沾点边的题.考虑1~n的素数个数为x.那么小于等于x的集合我们都可以找到全是素数的集合作为反例.那么只要输出x+2即可(1也要算上去).
代码:
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
int num = 2;
fir(i,2,n){
bool f = 1;
for(int j = 2;j*j <= i; ++ j){
if(i%j==0){
f = 0;
break;
}
}
num += f;
}
cout << (num>n?-1:num);
return 0;
}
E-牛牛的加法
模拟.注意一下扔掉前导零,而且保证ans.size()>=1(0+0 = 0).
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
string a,b;
cin >> a >> b;
if(a.size() < b.size()) swap(a,b);
int lena = a.size(),lenb = b.size();
string c;
int j = lenb-1;
afir(i,lena-1,0){
int x=0;
if(j>=0) x = b[j]-'0',j--;
x = (x+a[i]-'0')%10;
c += char(x+'0');
}
while(c.size() > 1 && c.back() == '0') c.pop_back();
reverse(ALL(c));
cout << c;
return 0;
}
F-石子合并
一个贪心题,显然每次都取最大的旁边两个之一,这样保证配对的和最大.
代码:
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int w[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
LL sum = 0;
int mx=0;
fir(i,1,n) cin >> w[i],sum += 1LL*w[i],mx=max(mx,w[i]);
sum -= 1LL*mx;
cout << sum+1LL*mx*(n-1) << "\n";
return 0;
}
E-滑板比赛
也是一道经典的贪心.只有一维的限制.每次二分找到第一个大于b[i]的就可以了.具体实现直接用multiset即可.
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int a[N],b[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
multiset<int> st;
fir(i,1,n) cin >> a[i],st.insert(a[i]);
fir(i,1,m) cin >> b[i];
int num = 0;
fir(i,1,m){
auto v = st.upper_bound(b[i]);
if(v == st.end()){
st.erase(st.begin());
continue;
}
num++;
st.erase(v);
}
cout << num;
return 0;
}
H-第 k 小
比赛的时候第一反应用平衡树敲.结果T了.其实直接用权值线段树即可.也可以用整体二分.
代码:
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e7+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
namespace seg{
int tot,ls[N],rs[N],sum[N];
void add(int &now,int l,int r,int p,int v){
if(!now) now = ++tot;
int mid = l + r >> 1;
sum[now]+=v;
if(l >= r) return;
if(p <= mid) add(ls[now],l,mid,p,v);
else add(rs[now],mid+1,r,p,v);
}
int ask(int now,int l,int r,int k){
if(l == r) return l;
int mid = l + r >> 1;
if(sum[ls[now]] >= k) return ask(ls[now],l,mid,k);
else return ask(rs[now],mid+1,r,k-sum[ls[now]]);
}
}
using namespace seg;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n,m,k,ro=0;
cin >> n >> m >> k;
fir(i,1,n){
int x;
cin >> x;
add(ro,0,1e9,x,1);
}
fir(i,1,m){
int op,x;
cin >> op;
if(op == 1){
n++;cin >> x;
add(ro,0,1e9,x,1);
}
else{
if(n < k){
cout << -1 << "\n";
continue;
}
cout << ask(ro,0,1e9,k) << "\n";
}
}
return 0;
}
I-区间异或
看到n才3000,直接枚举所有的区间,然后二分出第一个>=x的位置.然后就是一个后缀最大值问题.比赛的时候脑袋瓦特了用线段树维护.其实直接扫一遍即可.
代码:
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 1e7+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int a[N],ans[M];
pii vec[M];
int cnt;
int main(){
int n,m;
n = read();m = read();
fir(i,1,n) a[i] = read();
fir(i,1,n){
int sum = 0;
afir(j,i,1){
sum ^= a[j];
vec[++cnt] = mpr(sum,i-j+1);
}
}
sort(vec+1,vec+1+cnt);
ans[cnt+1] = INT_MAX;
afir(i,cnt,1) ans[i] = min(ans[i+1],vec[i].sd);
fir(i,1,m){
int x;
x = read();
int pos = lower_bound(vec+1,vec+1+cnt,mpr(x,-1))-vec;
if(pos == cnt+1) printf("-1\n");
else printf("%d\n",ans[pos]);
}
return 0;
}
J-小游戏
很简单的一道dp,按权值从大到小dp.dp[i]表示选了权值i能达到的max.转移方程dp[i] = max(dp[i+1],dp[i+2]+i*num[i]);
代码:
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
LL a[N],dp[N],num[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
fir(i,1,n) cin >> a[i],num[a[i]]++;
LL ans = 0;
afir(i,2e5,0){
dp[i] = max(dp[i+1],dp[i+2]+num[i]*i);
ans = max(ans,dp[i]);
}
cout << ans;
return 0;
}