https://icpc.qlu.edu.cn/contest/66ed8b746002253a77c10d5e
训练情况
场外 rk#2 AK
赛后反思
A题太菜了,没看出来是01背包DP,往前缀和上面想了,写了个假做法。
B题又不认真看题,忘记了 \(= 0\) 的情况。
C题博弈论乱猜
D题未考虑完全导致一次WA
A题
分两组,两组和相同,观察数据范围我们考虑 01 背包,先求出所有的和。显然,如果和为奇数则无法分组,当为偶数的时候,判断能否取出 \(\frac{sum}{2}\) 即可
#include <bits/stdc++.h>
#define int long longusing namespace std;const int N = 1e7 + 3;int dp[N];void solve(){int n; cin>>n;vector<int> a(n + 1);int sum = 0;dp[0] = 1;for(int i = 1;i<=n;i++) cin>>a[i],sum+=a[i];if(sum&1){cout<<"No"<<endl;return;}for(int i = 1;i<=n;i++){for(int j = sum/2;~j;j--){if(j-a[i] < 0) continue;if(dp[j-a[i]]) dp[j] = dp[j-a[i]];}}if(dp[sum/2]) cout<<"Yes"<<endl;else cout<<"No"<<endl;
}signed main(){// int T; cin>>T; while(T--)solve();return 0;
}
B题
找没被区间覆盖的点,考虑差分了再前缀和,坑点:\(0\) 也算。
#include <bits/stdc++.h>
#define int long longusing namespace std;const int N = 1e6 + 3;
int a[N];void solve(){int n,m; cin>>n>>m;for(int i = 1;i<=m;i++){int l,r; cin>>l>>r;a[l]++,a[r+1]--;}for(int i = 1;i<=n;i++) a[i]+=a[i-1];int ans = 0;for(int i = 0;i<=n;i++) if(!a[i]) ans++;cout<<ans<<endl;
}signed main(){// int T; cin>>T; while(T--)solve();return 0;
}
C题
逆天我不会的博弈论,逆天后手必胜的结论,通过玩 \(n \le 4\) 的样例,大胆猜测后手必胜
我又会了,后手有一个必胜策略,就是跟着先手的人走中心对称的那条边,最后出现一个正方形三条边的情况,直接去占即可
#include <bits/stdc++.h>
#define int long longusing namespace std;void solve(){cout<<"Tianmingren"<<endl;
}signed main(){// int T; cin>>T; while(T--)solve();return 0;
}
D题
考虑什么时候走不到 \(n\),当某一位为零的时候,并且前面的点没有办法跨过这个 \(0\)。维护一个最右的边界,同时遇到 \(0\) 判断即可,如果无法跨过答案就是 No,否则 Yes。
#include <bits/stdc++.h>
#define int long longusing namespace std;void solve(){int n; cin>>n;vector<int> a(n + 1);for(int i = 1;i<=n;i++) cin>>a[i];int last = 0;for(int i = 1;i<n;i++){if(a[i]) last = max(last,i+a[i]-1);if(!a[i] && last < i){cout<<"No"<<endl;return;}}cout<<"Yes"<<endl;
}signed main(){// int T; cin>>T; while(T--)solve();return 0;
}
E题
快读模板 + %99
#include <bits/stdc++.h>
#define int long longusing namespace std;inline int read(){int s = 0; char c = getchar();while(!isdigit(c)) c = getchar();while(isdigit(c)){s = (s << 1) + (s << 3) + (c ^ 48);s%=99;c = getchar();}return s;
}int ans = 0;void solve(){int x; x = read();if(!x) ans++;
}signed main(){int T; cin>>T; while(T--)solve();cout<<ans<<endl;return 0;
}
F题
模拟题,我们发现字母的位置是两倍的 \(i\) 或 \(j\),其他都是 # 号。
#include <bits/stdc++.h>
#define int long longusing namespace std;const int N = 8007;char ans[N][N];void solve(){int n,m; cin>>n>>m;vector<string> s(n + 1);for(int i = 0;i<n;i++) cin>>s[i];for(int i = 0;i<n;i++){for(int j = 0;j<m;j++){if(s[i][j] >= 'A' && s[i][j] <= 'Z') s[i][j]+=32;else s[i][j] -= 32;}}for(int i = 0;i<n;i++){for(int j = 0;j<m;j++){ans[(i+1)*2][(j+1)*2] = s[i][j];}}for(int i = 1;i<=2*n+1;i++){for(int j = 1;j<=2*m+1;j++){if(!ans[i][j]) ans[i][j] = '#';}}for(int i = 1;i<=n*2+1;i++){for(int j = 1;j<=m*2+1;j++){cout<<ans[i][j];}cout<<endl;}
}signed main(){// int T; cin>>T; while(T--)solve();return 0;
}
G题
单调不降,我们可以发现减少前面的较大值比增加后面的较小值要更优,减小前面的最大值会让数列变得更容易单调不降,维护一个当前的最大值(考虑 \(O(nlogn)\) 优先队列),若出现比他还小的替换掉当前最大值更新答案即可
#include <bits/stdc++.h>
#define int long longusing namespace std;priority_queue<int> q;int ans;void solve(){int x; cin>>x;q.push(x);if(x<q.top()){ans+=q.top()-x;q.pop();q.push(x);}
}signed main(){int T; cin>>T; while(T--)solve();cout<<ans<<endl;return 0;
}
H题
天数要向上取整,观察到取模有很好的周期性,把星期都偏移到 \(0 \sim 6\) 上,然后取模即可,然后再加回来
#include <bits/stdc++.h>
#define int long longusing namespace std;void solve(){int x,y,a; cin>>x>>y>>a;int add = (x+(y-1))/y;a--;a+=add;a%=7;a++;cout<<a<<endl;
}signed main(){// int T; cin>>T; while(T--)solve();return 0;
}