2026第二次周报
思维题还想的比较快,不过稍难一点的思维就出不来(E1 E2)
第七次个人赛
A
模拟即可。
string s;cin>>s;
set<char>ans;
for(int i=0;i<s.size();i++){
if(s[i]!=s[i+1])ans.insert(s[i]);
else i++;
}
for(auto p:ans)cout<<p;
cout<<endl;
B
思维题。如果所有串的长度为偶数,但1的个数为奇数,就必然会少一个回文串。其余都可满足。
int n,cnt,cnt1=0;
cin>>n;
vector<string >s(n+1);
for(int i=1;i<=n;i++){
cin >> s[i];
if(s[i].size()%2==0){
cnt++;
}
for(int j=0; j < s[i].size(); j++){
if(s[i][j]=='1'){
cnt1++;
}
}
}
if(cnt1%2){
if(cnt==n) cout<<n-1<<endl;
else cout<<n<<endl;
}
else{
cout<<n<<endl;
}
C
也是思维题。由题意知只能奇数之间排序交换,偶数之间交换。然后合并即可。
string s,s1,s2,ans;cin>>s;
for(int i=0;i<s.size();i++){
if(s[i]%2==0)s1+=s[i];
else s2+=s[i];
}
int i=0,j=0;
while(i<s1.size()&&j<s2.size()){
if(s1[i]<s2[j])ans+=s1[i],i++;
else ans+=s2[j],j++;
}
while(i<s1.size())ans+=s1[i++];
while(j<s2.size())ans+=s2[j++];
cout<<ans<<endl;
D
就是二分答案。先求出满足条件(至少 2n+1 个薪资大于或等于 mid),再二分最小的薪资。
CF题解:
让 f(mid) 等于获得至少 mid 的中位数薪资所需的最小金额。
假设需要计算获得至少 mid 的中位数薪资所需的最小金额。将所有薪资分为三组:
ri<mid;
mid≤li;
li<mid≤ri。
为了使中位数薪资至少为 mid,必须有至少 2n+1 个薪资大于或等于 mid。将这样的薪资数量记作 cnt。
注意,第一组的薪资无法增加 cnt 的值,第二组的薪资增加 cnt 的值,因此为这2组支付最低薪资都是有利的。
第三组中的每个薪资 [li,ri],可以支付 mid 并增加 cnt,或者我们可以支付 li 并不增加 cnt。
cnt 的值应增加 rem=max(0,2n+1−cnt)。
因此,如果第三组的大小小于 rem,那么我们无法获得中位数薪资 mid。否则,我们可以定义可以采用多少个值为 li 的薪资,并选择最小的那些。
bool ok(int mid){
long long sum = 0;
int cnt = 0;
vector <int> v;
for(int i = 0; i < n; ++i){
if(p[i].second < mid)
sum += p[i].first;
else if(p[i].first >= mid){
sum += p[i].first;
++cnt;
}
else
v.push_back(p[i].first);
}
assert(is_sorted(v.begin(), v.end()));
int need = max(0, (n + 1) / 2 - cnt);
if(need > v.size()) return false;
for(int i = 0; i < v.size(); ++i){
if(i < v.size() - need)
sum += v[i];
else
sum += mid;
}
return sum <= s;
}
E1
其实挺容易的。就是优先队列,不断选p最小的人贿赂。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int N=1e6+5;
const int mod=998244353;
struct node {
int m, p;
} a[N];
bool cmp(node a, node b) {
if (a.m == b.m)return a.p < b.p;
return a.m < b.m;
}
void solve(){
ll n,ans=0;cin >> n;
priority_queue<int, vector<int>, greater<int>> q;
for (int i = 1; i <= n; i++)cin >> a[i].m >> a[i].p;
sort(a + 1, a + 1 + n, cmp);
for (int i = n; i >= 1; i--) {
q.push(a[i].p);
if (a[i].m > n - q.size()) {
ans += q.top();
q.pop();
}
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
E2
优化一下,不能直接枚举人数了,想到按mi分组,再用multiset维护。
贴一下题解。

第六次个人赛
A
模拟再判断一下即可。
B
也是模拟,每个方针都判断一下再标记。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int N=55;
const int mod=998244353;
ll a[N][N],b[N][N],x[2555],y[2555];
void solve(){
int n,m,ans=0;cin>>n>>m;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
cin>>a[i][j];
}
}
memset(b,0,sizeof(b));
for (int i=1;i<n;i++){
for (int j=1;j<m;j++){
if (a[i][j]&&a[i+1][j]&&a[i][j+1]&&a[i+1][j+1]){
b[i][j]=1;
b[i+1][j]=1;
b[i][j+1]=1;
b[i+1][j+1]=1;
ans++;
x[ans]=i;
y[ans]=j;
}
}
}
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if (b[i][j]!=a[i][j]){
cout<<"-1\n";
return ;
}
}
}
cout<<ans<<endl;
for (int i=1;i<=ans;i++){
cout<<x[i]<<' '<<y[i]<<endl;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}
C
赛时模拟写出来了,但是,题解说是dp。。
贴一下题解和我自己的代码。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int N=3e5+5;
const int mod=998244353;
ll y[2555];
void solve(){
ll n,a,b;cin>>n>>a>>b;string s;cin>>s;
vector<int>f(n+1,0);
for (int i=0;i<n;i++){
if (s[i]=='1'){
f[i]=1;
f[i+1]=1;
}
}
int ff=0;
for (int i=0;i<=n;i++){
if (f[i]){
ff=1;
break;
}
}
if (!ff){
cout<<n*a+(n+1)*b<<endl;
return;
}
vector<int>h(n+1,-1);
for (int i=0;i<=n;i++){
if (f[i])h[i]=2;
}
h[0]=1;h[n]=1;
int fst=-1,lst=-1;
for (int i=0;i<=n;i++){
if (h[i] == 2){
if (fst == -1){
fst=i;
}
lst=i;
}
}
for (int i=0;i<fst;i++)h[i]=1;
for (int i=lst+1;i<=n;i++)h[i]=1;
int i=fst;
while (i <= lst){
int j=i+1;
while (j <= lst && h[j] != 2){
j++;
}
if (j > lst)break;
int k=j-i;
if (k*b<2*a+b){
for (int t=i+1;t<j;t++){
h[t]=2;
}
}
else{
for (int t=i+1;t<j;t++){
h[t]=1;
}
}
i=j;
}
ll ans=h[0]*b;
for (int i=0;i<n;i++){
if (h[i]==h[i+1]){
ans+=a;
}
else{
ans+=2*a;
}
ans+= h[i+1]*b;
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
第五次个人赛
难 而且感觉有点怪
A
乘以2的幂就是二进制左移运算,也就是说题目中的y*2^k其实是把二进制串y左移k位,空位补0。这样那串式子就只剩下了x+y。
求x+y翻转后的字典序最小:我们知道翻转后字典序最小可以转化为翻转前从前往后看字典序最小,再结合二进制加法1+1=0的性质,尽力把二进制串y最靠右的"1"通过加法变成"0"。
string x,y;cin>>x>>y;
reverse(x.begin(),x.end());
reverse(y.begin(),y.end());
int cnt=0;
while(cnt < y.size() && y[cnt]=='0') cnt++;
int k=cnt;
while(k < x.size() && x[k]=='0') k++;
cout<<k-cnt<<endl;
D
构造,感觉比A容易。
ll n,a=0,b=0;cin>>n;
string ans;
for(ll i=44722;i>=2;i--){
if(i*(i-1)/2<=n){
a=i;
b=n-i*(i-1)/2;
break;
}
}
ans+="133";
ans+=string (b,'7');
ans+=string (a-2,'3');
ans+='7';
cout<<ans<<endl;

浙公网安备 33010602011771号