609E - Minimum spanning tree for each edge(最小生成树+lca+倍增 *2100)
首先肯定会想到求最小生成树,记录用到的边
然后遍历所有边,如果当前边在最小生成树中,就直接输出最小生成树的权值,否则使用该边需要断开
u
,
v
u,v
u,v 路径的权值最大的边
路径上权值最大的边怎么求呢,路径一定是 lca 到 u 和 lca 到 v,所以求这两条链上的最大值就可以了,可以在倍增的同时更新最大值,这一题就解决了
#include<bits/stdc++.h>usingnamespace std;#defineintlonglongusing i64 =longlong;typedef pair<int,int> PII;typedef pair<int,char> PIC;typedef pair<double,double> PDD;typedef pair<int, PII> PIII;typedef pair<int, pair<int,bool>> PIIB;constint N =1e6+10;constint maxn =1e6+10;constint mod =1e9+7;constint mod1 =954169327;constint mod2 =906097321;constint INF =0x3f3f3f3f3f3f3f3f;structnode{int a, b, w, idx;};voidsolve(){int n, m;
cin >> n >> m;
vector<vector<PII>>g(n +1);
vector<node>edge(m);
vector<bool>st(m);// 这条边在不在最小生成树中for(int i =0; i < m; i ++){int a, b, c;
cin >> a >> b >> c;
edge[i]={a, b, c, i};}auto cmp1 =[&](node a, node b){return a.w < b.w;};sort(edge.begin(), edge.end(), cmp1);// 求最小生成树int mst =0;
vector<int>p(n +1);for(int i =1; i <= n; i ++) p[i]= i;
function<int(int)> find =[&](int x){if(p[x]!= x) p[x]=find(p[x]);return p[x];};auto cal_mst =[&](){for(int i =0; i < m; i ++){int a = edge[i].a, b = edge[i].b, w = edge[i].w, id = edge[i].idx;int pa =find(a), pb =find(b);if(pa != pb){
mst += w;
p[pa]= pb;
st[id]=true;
g[a].push_back({b, w});
g[b].push_back({a, w});}}};cal_mst();// 求uv到lca的最长边
vector<int>dep(n +1, INF);
vector<vector<int>>fa(n +1,vector<int>(20)),maxx(n +1,vector<int>(20));auto bfs =[&](int root){
dep[0]=0, dep[root]=1;
queue<int> q;
q.push(root);while(q.size()){auto t = q.front();
q.pop();for(int i =0; i < g[t].size(); i ++){int j = g[t][i].first, w = g[t][i].second;if(dep[j]> dep[t]+1){
dep[j]= dep[t]+1;
q.push(j);
fa[j][0]= t;
maxx[j][0]= w;for(int k =1; k <20; k ++){
fa[j][k]= fa[fa[j][k -1]][k -1];
maxx[j][k]=max(maxx[fa[j][k -1]][k -1], maxx[j][k -1]);}}}}};auto lca =[&](int a,int b){if(dep[a]< dep[b])swap(a, b);int ans =0;for(int k =19; k >=0; k --){if(dep[fa[a][k]]>= dep[b]){
ans =max(ans, maxx[a][k]);
a = fa[a][k];}}if(a == b)return ans;for(int k =19; k >=0; k --){if(fa[a][k]!= fa[b][k]){
ans =max({ans, maxx[a][k], maxx[b][k]});
a = fa[a][k];
b = fa[b][k];}}
ans =max({ans, maxx[a][0], maxx[b][0]});return ans;};bfs(1);// 输出答案auto cmp2 =[&](node a, node b){return a.idx < b.idx;};sort(edge.begin(), edge.end(), cmp2);for(int i =0; i < m; i ++){if(st[i]) cout << mst <<'\n';else{int a = edge[i].a, b = edge[i].b, w = edge[i].w;
cout << mst -lca(a, b)+ w <<'\n';}}}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t--){solve();}}
B2 - Bouquet (Hard Version)(思维)
昨晚cf的一题
因为同时选
x
x
x 和
x
+
1
x+1
x+1,可以贪心全部选
x
x
x,剩下的钱贪心选
x
+
1
x+1
x+1,如果还有多的钱就把
x
x
x 换成
x
+
1
x+1
x+1
#include<bits/stdc++.h>usingnamespace std;#defineintlonglongusing i64 =longlong;typedef pair<int,int> PII;typedef pair<int,char> PIC;typedef pair<double,double> PDD;typedef pair<int, PII> PIII;typedef pair<int, pair<int,bool>> PIIB;constint N =1e6+10;constint maxn =1e6+10;constint mod =1e9+7;constint mod1 =954169327;constint mod2 =906097321;constint INF =0x3f3f3f3f3f3f3f3f;voidsolve(){int n, m;
cin >> n >> m;
vector<int>a(n +1);
map<int,int> mp;for(int i =1; i <= n; i ++) cin >> a[i];for(int i =1; i <= n; i ++){int x; cin >> x;
mp[a[i]]= x;}int ans =0;for(auto t : mp){int num1 = t.first, cnt1 = t.second;int tmp;if(mp.count(num1 +1)==0){int c = m / num1;
c =min(c, cnt1);
tmp = c * num1;}else{int num2 = num1 +1;int cnt2 = mp[num2];int c1 = m / num1;
c1 =min(c1, cnt1);int have = m - c1 * num1;int c2 = have / num2;
c2 =min(c2, cnt2);
have = have - c2 * num2;
cnt2 -= c2;int tt =min({cnt2, have, c1});
c1 -= tt, c2 += tt;
tmp = c1 * num1 + c2 * num2;}
ans =max(ans, tmp);}
cout << ans <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;
cin >> t;while(t--){solve();}}
D - Cases(状压dp)
数据范围给的就很状压dp,但是昨晚一直没想到怎么更新
原问题可以转化成,任意连续的
k
k
k 个子串中必须有一个终止字符,我们求出所有长度为
k
k
k 的子串中包含的元素集合,用二进制表示,标记为不合法,那么其余的就一定合法,计算1的个数即可
#include<bits/stdc++.h>usingnamespace std;#defineintlonglongusing i64 =longlong;typedef pair<int,int> PII;typedef pair<int,char> PIC;typedef pair<double,double> PDD;typedef pair<int, PII> PIII;typedef pair<int, pair<int,bool>> PIIB;constint N =1e6+10;constint maxn =1e6+10;constint mod =1e9+7;constint mod1 =954169327;constint mod2 =906097321;constint INF =0x3f3f3f3f3f3f3f3f;voidsolve(){int n, c, k;
cin >> n >> c >> k;
string s; cin >> s;
s =" "+ s;
vector<int>cnt(26);
vector<bool>dp((1ll<< c)+1);
dp[1<<(s[n]-'A')]=1;int state =0;int r =0;for(int i =1; i + k -1<= n; i ++){if(i !=1){
cnt[s[i -1]-'A']--;if(cnt[s[i -1]-'A']==0) state ^=(1<<(s[i -1]-'A'));}while(r < i + k -1){
r ++;
cnt[s[r]-'A']++;if(cnt[s[r]-'A']==1) state ^=(1<<(s[r]-'A'));}
dp[state]=true;}for(int i =0; i < c; i ++){for(int j =0; j <(1<< c); j ++){if((j >> i)&1) dp[j]=(dp[j]| dp[j ^(1<< i)]);}}int base =((1ll<< c)-1);int ans = INF;for(int i =0; i <(1<< c); i ++){if(!dp[i]) ans =min(ans,(i64)(__builtin_popcount(base ^ i)));}
cout << ans <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;
cin >> t;while(t--){solve();}}