传送门:
Toyota Programming Contest 2023#7(AtCoder Beginner Contest 328) - AtCoder
本章对于自己的提升:dfs的运用,带权并查集,以及状压dp。
A,B,C题比较简单,直接附上代码。
A - Not Too Hard
// #pragma GCC optimize(3) //O2优化开启
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PII;
const int mod=998244353;
int b[1000005];
int n,x;
void icealsoheat(){cin>>n>>x;int ans=0;for(int i=1;i<=n;i++)cin>>b[i];for(int i=1;i<=n;i++){ans+=b[i]<=x?b[i]:0ll;}cout<<ans;
}
signed main(){ios::sync_with_stdio(false);cin.tie();cout.tie();int _yq;_yq=1;// cin>>_yq;while(_yq--){icealsoheat();}
}
B - 11/11
// #pragma GCC optimize(3) //O2优化开启
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PII;
const int mod=998244353;
int b[1000005];
int n,x;
void icealsoheat(){cin>>n;int ans=0;for(int i=1;i<=n;i++)cin>>b[i];for(int i=1;i<=n;i++){// if(b[i]>=i)ans++;int x=i%10;int an=i;bool f=0;while(an){if(an%10!=x){f=1;break;}an/=10;}if(f)continue;int bn=x;while(b[i]>=bn){ans++;bn=bn*10+x;}}cout<<ans;
}
signed main(){ios::sync_with_stdio(false);cin.tie();cout.tie();int _yq;_yq=1;// cin>>_yq;while(_yq--){icealsoheat();}
}
C - Consecutive
// #pragma GCC optimize(3) //O2优化开启
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PII;
const int mod=998244353;
int b[1000005];
int n,q;
string s;
int sum[1000005];
void icealsoheat(){cin>>n>>q;cin>>s;s=' '+s;for(int i=2;i<=n;i++){if(s[i]==s[i-1]){sum[i]=sum[i-1]+1;}else sum[i]=sum[i-1];}while(q--){int l,r;cin>>l>>r;int ans=sum[r]-sum[l-1];if(s[l]>1&&s[l]==s[l-1]){ans--;}cout<<ans<<"\n";}
}
signed main(){ios::sync_with_stdio(false);cin.tie();cout.tie();int _yq;_yq=1;// cin>>_yq;while(_yq--){icealsoheat();}
}
D - Take ABC
// #pragma GCC optimize(3) //O2优化开启
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PII;
const int mod=998244353;
// int b[1000005];
int n,q;
string s;
int sum[1000005];
void icealsoheat(){string s;cin>>s;vector<char>b;for(auto i:s){if(i!='C'||b.size()<2){b.push_back(i);}else{int id=b.size();if(b[id-1]=='B'&&b[id-2]=='A'){b.pop_back();b.pop_back();}else{b.push_back(i);}}}for(auto i:b){cout<<i;}}
signed main(){ios::sync_with_stdio(false);cin.tie();cout.tie();int _yq;_yq=1;// cin>>_yq;while(_yq--){icealsoheat();}
}
E - Modulo MST
这题要求是找边权经行取模后的(注意是取模后的数值)最小的最小生成树。此处的边的数量就未必是n-1了。我们需要用dfs把所有可能都跑一遍,并找到能把所有点能链接的最小生成树的最小的边权。(我没有想到会用这么暴力的写法,时间复杂度计算有待提高,赛时没有做出来)。在这里偷了jiangly的并查集板子。并查集用于查询到底有多少个点被取到了。应为他把并查集用了一个结构体进行递归,所以使得他的并查集可以迭代,很巧妙。
// #pragma GCC optimize(3) //O2优化开启
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PII;
const int mod=998244353;int u[1000005];
int v[1000005];
int w[1000005];
struct DSU {std::vector<int> f, siz;DSU() {}DSU(int n) {init(n);}void init(int n) {f.resize(n);std::iota(f.begin(), f.end(), 0);// for(int i=1;i<=n;i++)f[i]=i;siz.assign(n, 1);}int find(int x) {while (x != f[x]) {x = f[x] = f[f[x]];}return x;}bool same(int x, int y) {return find(x) == find(y);}bool merge(int x, int y) {x = find(x);y = find(y);if (x == y) {return false;}siz[x] += siz[y];f[y] = x;return true;}int size(int x) {return siz[find(x)];}
};
int n,m,k;
void icealsoheat(){cin>>n>>m>>k;for(int i=1;i<=m;i++){cin>>u[i]>>v[i]>>w[i];}int ans=k;auto dfs=[&](auto self,int i,DSU dsu,int s)->void{if(i==m+1){bool f=0;for(int i=1;i<=n;i++){if(!dsu.same(i,1)){f=1;break;}}if(!f)ans=min(ans,s%k);return;}self(self,i+1,dsu,s);if(!dsu.same(u[i],v[i])){dsu.merge(u[i],v[i]);self(self,i+1,dsu,s+w[i]);}};dfs(dfs,1,DSU(n+5),0);cout<<ans;}
signed main(){ios::sync_with_stdio(false);cin.tie();cout.tie();int _yq;_yq=1;// cin>>_yq;while(_yq--){icealsoheat();}
}
F - Good Set Query
这题是一道很典型的带权并查集的板子题,但我当时带权并查集忘却了,这里让我查漏补缺了。
代码如下:
// #pragma GCC optimize(3) //O2优化开启
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PII;
const int mod=998244353;
int n,q;
int w[1000005];
int pre[1000005];
// int a[1000005];
int find(int x){if(x==pre[x])return x;int t=pre[x];pre[x]=find(pre[x]);w[x]+=w[t];// pre[x]=find(pre[x]);return pre[x];}void icealsoheat(){cin>>n>>q;for(int i=1;i<=n;i++)pre[i]=i;for(int i=1;i<=q;i++){int a,b,d;cin>>a>>b>>d;int xx=find(a);int yy=find(b);if(xx==yy&&w[a]-w[b]==d)cout<<i<<" ";else if(xx!=yy){pre[yy]=xx;w[yy]+=w[a]-d-w[b];cout<<i<<" ";}}}
signed main(){ios::sync_with_stdio(false);cin.tie();cout.tie();int _yq;_yq=1;// cin>>_yq;while(_yq--){icealsoheat();}
}
G - Cut and Reorder
这题题目没看懂啥意思。
这里我看了大佬的题解Toyota Programming Contest 2023#7(AtCoder Beginner Contest 328) - 知乎 (zhihu.com)
这个数据一看到n<=22,就该第一时间想到,这很状压,但我思维太过浅薄,没有想到如何迭代状态。看了佬的题解才明白。
代码如下:
// #pragma GCC optimize(3) //O2优化开启
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PII;
const int mod=998244353;
int n,c;
int a[10005];
int b[10005];
void icealsoheat(){cin>>n>>c;for(int i=0;i<n;i++)cin>>a[i];for(int i=0;i<n;i++)cin>>b[i];vector<int>dp((1<<n)+5,0x3f3f3f3f3f3f3f3f);dp[0]=-c;for(int i=0;i<(1<<n);i++){int cnt=__builtin_popcount(i);for(int j=0;j<n;j++){if(!(i>>j&1)){int k=j;int sum=0;int ns=i;int id=0;while(k<n&&!(i>>k&1)&&cnt+id<n){ns|=(1ll<<k);sum+=abs(a[k]-b[cnt+id]);id++;k++;// ns|=(1ll<<k);dp[ns]=min(dp[ns],dp[i]+sum+c);}}}}cout<<dp[(1<<n)-1];}
signed main(){ios::sync_with_stdio(false);cin.tie();cout.tie();int _yq;_yq=1;// cin>>_yq;while(_yq--){icealsoheat();}
}