3.24~3.30
牛客周赛86
A

签到
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int x,y;
cin >> x >> y;
cout << (y%x ? y/x+1 : y/x) << '\n';
return 0;
}
B

贪心,很明显删除全部负数就可以使总和最大,也就是把正数相加
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 2e5+1;
signed main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin >> t;
while(t--){
int n,k;
cin >> n >> k;
int sum =0,cache;
for(int i=0;i<n;i++){
cin >> cache;
if(cache > 0)
sum += cache;
}
cout << sum << '\n';
}
return 0;
}
C

自己写几个例子就会发现:
两个相邻的数相同,删删删
删到最后一定是0101或1010这种相邻不相同的,那么操作次数就是这种串的长度整除2
用栈/队列等都可实现
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin >> t;
while(t--){
int n;
string str;
cin >> n >> str;
stack <char> s;
for(auto c:str){
if(!s.empty() && s.top() == c)
s.pop();
else s.push(c);
}
cout << s.size() / 2 << '\n';
}
return 0;
}
D

构造。可以发现,操作次数最多为三,因为如果不能一次过,那么第一次和第二次构造两个相同的数,第三次进行^,一定为0
操作次数为1的情况:
x == y或者 x&y == 0
操作次数为2的情况:
令对x和y做四种操作之一后,结果为a
a == xora == yora&x == 0ora&y == 0
其余的就是操作次数为3
#include <bits/stdc++.h>
using namespace std;
void solve(int x,int y){
if(x == y || (x&y)==0){
cout << "1\n";
return;
}
int a = x&y, b = x|y, c = x^y, d = __gcd(x,y);
if((a&y)==0 || (a&x)==0 || a==y || a==x || (b&y)==0 || (b&x)==0 || b==y || b==x || (c&y)==0 || (c&x)==0 || c==y || c==x || (d&y)==0 || (d&x)==0 || d==y || d==x){
cout << "2\n";
return;
}
cout << "3\n";
return;
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin >> t;
while(t--){
int x,y;
cin >> x >> y;
solve(x,y);
}
return 0;
}
背包练习
想找dp练练,但是找的第一题是个裸背包,后面不裸
(此题可忽略!)以下是第一题

#include <bits/stdc++.h>
using namespace std;
int c[101],w[101],dp[101][1001];
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t,m;
cin >> t >> m;
for(int i=1;i<=m;i++)
cin >> c[i] >> w[i];
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;i++){
for(int j=1;j<=t;j++){
if(j>=c[i]) dp[i][j] = max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);
else dp[i][j] = dp[i-1][j];
}
}
cout << dp[m][t] << '\n';
return 0;
}
第二题

有点难度的,并查集+dp,还要优化,不然要MLE(亲身体验过)
如上,方法就是并查集+dp
但是n最大时1e4,常规背包就是1e8,大概100MB,会MLE,所以用滚动数组优化
并查集也有优化,每次合并都需要矮树合并到高树,否则祖先就不对
路径压缩也要单独拎出来写,不能像原来一样揉到find_s里,因为不只是tree[i]的祖先要更新,相应的价钱和价值也要一起更新
调试比较多
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+1;
int tree[maxn],high[maxn]={0},c[maxn],w[maxn],dp[maxn];
int true_c[maxn]={0},true_w[maxn]={0};
void __init__(){
for(int i=1;i<=maxn;i++)
tree[i] = i;
}
int find_s(int x){
return (x==tree[x] ? x : find_s(tree[x]));
}
void union_s(int a,int b){
int x = find_s(a);
int y = find_s(b);
if(x == y) return;
if(high[x] == high[y]){
high[x] += 1;
c[tree[x]] += c[tree[y]];
w[tree[x]] += w[tree[y]];
tree[y] = x;
}
else{
if(high[x] < high[y]){
c[tree[y]] += c[tree[x]];
w[tree[y]] += w[tree[x]];
tree[x] = y;
}
else{
c[tree[x]] += c[tree[y]];
w[tree[x]] += w[tree[y]];
tree[y] = x;
}
}
/*if(x!=y){
tree[x] = tree[y];
c[tree[x]] += c[tree[y]];
w[tree[x]] += w[tree[y]];
}*/
}
void update(int n){
for(int i=1;i<=n;i++){
int root = find_s(i);
if(tree[i] != root){
c[root] += c[tree[i]];
w[root] += w[tree[i]];
tree[i] = root;
}
}
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
__init__();
memset(dp,0,sizeof(dp));
int n,m,money;
cin >> n >> m >> money;
for(int i=1;i<=n;i++)
cin >> c[i] >> w[i];
for(int i=1;i<=m;i++){
int u,v;
cin >> u >> v;
union_s(u,v);
}
for(int i=1;i<=n;i++){
if(!true_c[tree[i]])
true_c[tree[i]] = c[tree[i]];
if(!true_w[tree[i]])
true_w[tree[i]] = w[tree[i]];
}
update(n);
for(int i=1;i<=n;i++){
for(int j=money;j>=c[i];j--){
dp[j] = max(dp[j],dp[j-true_c[i]]+true_w[i]);
}
}
//for(int i=1;i<=n;i++){
// cout << tree[i] << '\n';
//}
//for(int i=1;i<=money;i++)
// cout << dp[i] << '\n';
//for(int i=1;i<=n;i++){
// cout << true_w[i] << ' ';
//}
cout << dp[money] << '\n';
return 0;
}

浙公网安备 33010602011771号