2023 团体程序设计天梯赛 L1,L2,L3-2
7-1 最好的文档
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
cout<<"Good code is its own best documentation.";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-2 什么是机器学习
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int a,b;
cin>>a>>b;
cout<<a+b-16<<endl<<a+b-3<<endl<<a+b-1<<endl<<a+b;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-3 程序员买包子
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,m,k;
string x;
cin>>n>>x>>m>>k;
if(k==n){
cout<<"mei you mai "<<x<<" de";
}
else if(k==m){
cout<<"kan dao le mai "<<x<<" de";
}
else{
cout<<"wang le zhao mai "<<x<<" de";
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-4 进化论
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int a,b,c;
cin>>a>>b>>c;
if(c==a*b){
cout<<"Lv Yan";
}
else if(c==a+b){
cout<<"Tu Dou";
}
else{
cout<<"zhe du shi sha ya!";
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
7-5 猜帽子游戏
用 \(f\) 记录有几个人不猜,如果 \(f>=n\) 则代表所有人都没猜。
如果某个人猜错了,则直接令 \(f=n\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
int k;
cin>>k;
while(k--){
vector<int> b(n+1);
int f=0;
for(int i=1;i<=n;i++){
cin>>b[i];
if(b[i]==0) f++;
else if(b[i]!=a[i]) f=n;
}
if(f>=n) cout<<"Ai Ya";
else cout<<"Da Jiang!!!";
cout<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-6 剪切粘贴
字符串题,无各种函数纯手搓。
技巧是新开一个字符串临时存储中间字符串,不要试图直接在原字符串上做操作
注意 .size() 是无符号整型,做减法可能会溢出
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
string s;
cin>>s;
int q;
cin>>q;
while(q--){
int l,r;
cin>>l>>r;
l--,r--;
string ts,t,a,b;
for(int i=l;i<=r;i++){
t.push_back(s[i]);
}
for(int i=0;i<l;i++){
ts.push_back(s[i]);
}
for(int i=r+1;i<s.size();i++){
ts.push_back(s[i]);
}
s=ts;
ts.clear();
cin>>a>>b;
b=a+b;
int idx=-1;
for(int i=0;i<(int)s.size()-(int)b.size()+1;i++){
for(int j=i;j<=i+b.size()-1;j++){
if(s[j]!=b[j-i]) break;
if(j==i+b.size()-1){
idx=i;
}
}
if(idx!=-1) break;
}
if(idx==-1){
s+=t;
continue;
}
idx+=a.size();
for(int i=0;i<idx;i++){
ts.push_back(s[i]);
}
ts+=t;
for(int i=idx;i<s.size();i++){
ts.push_back(s[i]);
}
s=ts;
}
cout<<s;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-7 分寝室
直接从 \(1\) 到 \(n-1\) 循环一遍,女生分 \(i\) 间,男生分 \(n-i\) 间
对于每一个 \(i\),判断是否会出现单人寝室,判断是否可以平分。
对于所有合法的 \(i\),取一个男女差值最小的即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int a,b,n;
cin>>a>>b>>n;
priority_queue<array<int,3>,vector<array<int,3>>,greater<array<int,3>>> q;
for(int i=1;i<n;i++){
if(a%i!=0 || b%(n-i)!=0) continue;
if(a==i || b==(n-i)) continue;
int x=a/i,y=b/(n-i);
int diff=abs(x-y);
q.push({diff,i,n-i});
}
if(q.size()){
auto [diff,x,y]=q.top();
cout<<x<<" "<<y;
}
else cout<<"No Solution";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-8 谁管谁叫爹
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int a,b,sa=0,sb=0;
cin>>a>>b;
int ta=a,tb=b;
bool f1=0,f2=0;
while(ta){
sa+=ta%10;
ta/=10;
}
while(tb){
sb+=tb%10;
tb/=10;
}
if(a%sb==0){
f1=1;
}
if(b%sa==0){
f2=1;
}
if(f1==f2){
if(a>b) cout<<"A";
else cout<<"B";
}
else if(f1) cout<<"A";
else cout<<"B";
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
7-9 堆宝塔
按照题意模拟即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
int ans=0,mx=0;
vector<int> a,b;
while(n--){
int val;
cin>>val;
if(a.size()==0 || val<a.back()) a.push_back(val);
else if(b.size()==0 || val>b.back()) b.push_back(val);
else{
ans++;
mx=max(mx,(int)a.size());
a.clear();
while(b.size() && b.back()>val){
a.push_back(b.back());
b.pop_back();
}
a.push_back(val);
}
}
if(a.size()){
ans++;
mx=max((int)a.size(),mx);
}
if(b.size()){
ans++;
mx=max((int)b.size(),mx);
}
cout<<ans<<" "<<mx;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-10 天梯赛的赛场安排
依旧是小模拟,合理使用 STL 可以大幅简化代码
将每个学校按照 {剩余人数,学校} 的形式,存入优先队列中,每次去除剩余人数最多的学校
如果人数大于等于 \(n\),则需要新开一个考场,然后将剩余人数放回优先队列里
否则按照考场号从小到大,找一个剩余座位数量能放的下的考场,放进去,同时更新这个考场的剩余座位数。
否则新开一个考场,同时更新这个考场的剩余座位数。
点击查看代码
#include<bits/stdc++.h>
// #define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,c,now=0;
cin>>n>>c;
vector<pair<string,int>> sc(n+1);
priority_queue<pair<int,string>> q1;//{剩余人数,学校}
vector<int> b(100001);
map<string,int> mp;
for(int i=1;i<=n;i++){
cin>>sc[i].first>>sc[i].second;
q1.push({sc[i].second,sc[i].first});
}
while(q1.size()){
auto [cnt,name]=q1.top();
q1.pop();
mp[name]++;
if(cnt>=c){
cnt-=c;
++now;
if(cnt!=0) q1.push({cnt,name});
}
else{
bool f=0;
for(int i=1;i<=now;i++){
if(b[i]>=cnt){
b[i]-=cnt;
f=1;
break;
}
}
if(f) continue;
now++;
b[now]=c-cnt;
}
}
for(int i=1;i<=n;i++){
cout<<sc[i].first<<" "<<mp[sc[i].first]<<endl;
}
cout<<now;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-11 锦标赛
用 \(cur\) 数组维护当前还剩余的空位,对于某一轮的第 \(j\) 比赛,胜者和败者一定是从 \(prel=cur[2*j-1]\) 和 \(prel=cur[2*j]\) 中来的
现在需要做的是,给败者和胜者放进这两个空位中
限制条件是什么?
这两个空位,不管在当前轮次是胜者还是败者,它在之前的轮次,一定一直是胜者,需要击败很多人,可以用 \(limit\) 数组维护,每个位置之前击败的敌人数值的最大值。
如果要把败者放进 \(prer\),则需要满足败者的数值大于等于 \(limit[prer]\)。 \(prel\) 同理
所以要找一个满足条件的位置放进去,放进去后,另一个位置的限制条件需要用败者的数值更新。
如果某一次,两个位置都放不进去,则非法
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int k;
cin>>k;
int n=1<<k;
vector<int> a(n+1);
vector rd(k+1,vector<int>());
for(int i=1;i<=k;i++){
int cnt=1<<(k-i);
rd[i].push_back(0);
for(int j=1;j<=cnt;j++){
int val;
cin>>val;
rd[i].push_back(val);
}
}
int win;
cin>>win;
vector<int> cur(n+1),limit(n+1);
iota(cur.begin()+1,cur.end(),1);
for(int i=1;i<=k;i++){
vector<int> tmp;//下一轮的幸存者
tmp.push_back(0);
int cnt=rd[i].size()-1;//这一轮的比赛数
for(int j=1;j<=cnt;j++){
int loser=rd[i][j];
int prel=cur[2*j-1];
int prer=cur[2*j];
if(loser>=limit[prel]){
a[prel]=loser;
limit[prer]=max(loser,limit[prer]);
// limit[prer]=loser;
tmp.push_back(prer);
}
else if(loser>=limit[prer]){
a[prer]=loser;
limit[prel]=max(loser,limit[prel]);
// limit[prel]=loser;
tmp.push_back(prel);
}
else{
cout<<"No Solution";
return;
}
}
cur=tmp;
}
int pos=limit[1];
if(win<limit[cur[1]]){
cout<<"No Solution";
return;
}
a[cur[1]]=win;
cout<<a[1];
for(int i=2;i<=n;i++){
cout<<" "<<a[i];
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-12 寻宝图
\(BFS\) 找到所有岛屿,对于每个岛屿,判断有没有宝藏即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};
void solve(){
int n,m;
cin>>n>>m;
vector<vector<int>> g(n+1,vector<int>(m+1)),st(n+1,vector<int>(m+1));
int cnt1=0,cnt2=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch;
cin>>ch;
g[i][j]=ch-'0';
}
}
auto dfs2=[&](auto dfs2,int x,int y,int &mk)-> void {
st[x][y]=1;
if(g[x][y]>1 && mk==0){
cnt2++;
mk=1;
}
for(int i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a<1 || a>n || b<1 || b>m) continue;
if(st[a][b] || g[a][b]==0) continue;
dfs2(dfs2,a,b,mk);
}
};
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(st[i][j] || g[i][j]==0) continue;
cnt1++;
int mk=0;
dfs2(dfs2,i,j,mk);
}
}
cout<<cnt1<<" "<<cnt2;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
7-14 完美树
天梯赛为数不多的好题,树形 DP
设 \(f[u] [0]\) 表示,以 \(u\) 为根节点的子树,使得所有节点中,\(0\) 比 \(1\) 多一个的最小代价
设 \(f[u] [1]\) 表示,以 \(u\) 为根节点的子树,使得所有节点中,\(1\) 比 \(0\) 多一个的最小代价
设 \(f[u] [2]\) 表示,以 \(u\) 为根节点的子树,使得所有节点中,\(1\) 和 \(0\) 一样多的最小代价
显然,对于 \(sz[u]\) 为偶数的节点,只有 \(f[u] [0]\) 有意义。
对于对于 \(sz[u]\) 为奇数的节点,只有 \(f[u] [1]\) 和 \(f[u] [2]\) 有意义。
计算完 \(u\) 的所有子节点 \(v\) 的值后,考虑如何计算 \(u\) 的值
首先对于 \(sz[v]\) 为偶数的点,只能使用 \(f[v] [2]\)
对于 \(sz[v]\) 为奇数的点,先全选 \(f[v] [1]\),并收集将每个 \(f[u] [1]\) 变成 \(f[u] [2]\) 的最小代价,使用尽可能小的代价,将一些 \(f[u] [1]\) 变成 \(f[u] [0]\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<vector<int>> g(n+1);
vector<int> p(n+1),c(n+1);
////f[i][2]:一样多 f[i][1]:1比0多 f[i][0]:0比1多
vector<array<int,3>> f(n+1,{inf,inf,inf});
for(int u=1;u<=n;u++){
int k;
cin>>c[u]>>p[u]>>k;
while(k--){
int v;
cin>>v;
g[u].push_back(v);
}
}
vector<int> sz(n+1);
auto dfs=[&](auto dfs,int u)->void {
sz[u]=1;
if(g[u].size()==0){
f[u][c[u]]=0;
f[u][c[u]^1]=p[u];
return;
}
int val=0;
vector<int> tmp;
for(auto v:g[u]){
dfs(dfs,v);
sz[u]+=sz[v];
if(sz[v]%2==0){
val+=f[v][2];
}
else{
val+=f[v][1];
tmp.push_back(f[v][1]-f[v][0]);//先假设所有奇子树都选1比0多
}
}
if(c[u]==0){
val+=p[u];
tmp.push_back(p[u]);
}
else{
tmp.push_back(-p[u]);
}
sort(tmp.begin(),tmp.end(),greater<int>());
int k=tmp.size();
if(sz[u]%2==0){
for(int i=0;i<k/2;i++){
val-=tmp[i];
}
f[u][2]=val;
}
else{
for(int i=0;i<k/2;i++){
val-=tmp[i];
}
f[u][1]=val;
val-=tmp[k/2];
f[u][0]=val;
}
};
dfs(dfs,1);
cout<<min({f[1][0],f[1][1],f[1][2]});
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}

浙公网安备 33010602011771号