2026 WINTER 2nd
总
这次补题觉得有收获的是
r5 b的问题抽象成一个最短路径 d
r6 c d
r7 d e
补题
r5
A. You Are Given Two Binary Strings...
尽量让最后几位成0
点击查看代码
void solve()
{
string x,y;
cin>>x>>y;
int cnt=0,ans=0;
for(int i=y.size()-1;i>=0;i--)
if(y[i]=='0') cnt++;
else break;
for(int i=x.size()-cnt-1;i>=0;i--)
if(x[i]=='0') ans++;
else break;
cout<<ans;
}
B. You Are Given a Decimal String...
可抽象成模10状态图上最短路径问题
每个状态表示当前个位数字,从状态i可一步转移到(i+x)mod10或(i+y)mod10。先统计字符串中所有相邻数字对的出现次数,对每一组(x,y) 用FLoyd预处理 10 个状态之间的最短步数,若存在某对相邻字符不可达则该方案无解;否则对所有相邻对累加(最短步数−1)×出现次数,即可得到最少插入次数,从而在O(n+1000) 的时间复杂度内求出全部 10×10的答案矩阵
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
int n;
string s;
int cnt[30][30],dis[15][15];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>s;
int n=s.size();
for(int i=1;i<n;i++)
cnt[s[i-1]-'0'][s[i]-'0']++;
for(int x=0;x<=9;x++,puts(""))
for(int y=0;y<=9;y++)
{
memset(dis,0x3f,sizeof(dis));
for(int i=0;i<=9;i++)
{
dis[i][(i+x)%10]=1;
dis[i][(i+y)%10]=1;
}
for(int k=0;k<=9;k++)
for(int i=0;i<=9;i++)
for(int j=0;j<=9;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
long long ans=0;
bool flag=true;
for(int i=0;i<=9;i++)
for(int j=0;j<=9;j++)
{
if(cnt[i][j]>0&&dis[i][j]==0x3f3f3f3f)
flag=false;
else
ans+=(dis[i][j]-1)*cnt[i][j];
}
printf("%lld ",!flag?-1:ans);
}
return 0;
}
D. Print a 1337-string...
https://www.luogu.com.cn/article/n7lvewoz
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
#define modd 998244353
const ll N = 2e5+10;
static const ll INF = (ll)4e18;
void solve() {
ll k=300;
ll n;cin>>n;
ll t1=k*(k+1)/2;
ll t=n/t1;
ll tmp=n-t1*t;
cout<<"133";
for(ll i=1;i<=tmp;++i) cout<<'7';
for(ll i=1;i<k;++i) cout<<'3';
for(ll i=1;i<=t;++i) cout<<'7';
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll lll = 1;
cin >> lll;
while (lll--) {
solve();
if (lll) cout << '\n';
}
return 0;
}
r6
A. There Are Two Types Of Burgers
取h和c最大的,先把面包胚全分给多的,再考虑小的
B. Square Filling
这题最开始没注意审题,题目说了不要求最小化答案,按着最小化答案做的。。
如果不要求最小化的话,其实按照a数组一步一步去填b数组就好了,同时记录操作
C. Gas Pipeline
用的dp,核心思路是跟踪管道在每个位置的两种高度状态,通过状态转移逐步求解最小成本
实现的一些细节写在代码里了
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
#define modd 998244353
const ll N = 2e5+10;
static const ll INF = (ll)4e18;
void solve() {
ll n,a,b;string s;
cin>>n>>a>>b>>s;
vector<vector<ll>> f(n,vector<ll>(2,INF));
f[0][0]=a+b;
f[0][1]=INF;//初始时(坐标0)必须在高度1,无法在2,所以设成最大值
for(ll i=1;i<n;++i){
if(s[i]=='1'){//必须在高度2
f[i][0]=INF;
f[i][1]=min(f[i-1][0]+2*a+2*b,f[i-1][1]+a+2*b);//1->2,2->2
}else{
f[i][0]=min(f[i-1][0]+a+b,f[i-1][1]+2*a+2*b);//0->0,1->0
f[i][1]=min(f[i-1][0]+2*a+b,f[i-1][1]+a+2*b);//0->1,1->1
}
}
cout<<f[n-1][0]+b;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll lll = 1;
cin >> lll;
while (lll--) {
solve();
if (lll) cout << '\n';
}
return 0;
}
D. Number Of Permutations
这个还挺好想的,用容斥原理
总排列数-按第一维非递减排序的排列数-按第二维非递减排序的排列数+同时按第一维、第二维都非递减的排列数
记得加上同时的情况
主要是代码写法上差错了点。。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
#define modd 998244353
const ll N = 3e5+10;
static const ll INF = (ll)4e18;
ll fact[N];
void solve() {
ll n;cin>>n;
vector<pair<ll,ll>>s(n);
for(ll i=0;i<n;++i){
cin>>s[i].first>>s[i].second;
}
fact[0]=1;
for(ll i=1;i<=n;++i){
fact[i]=fact[i-1]*i%modd;
}
vector<ll>cnta(n+1,0),cntb(n+1,0);
for(auto &p:s){
cnta[p.first]++;
cntb[p.second]++;
}
ll a=1,b=1;
for(ll i=1;i<=n;++i){
a=a*fact[cnta[i]]%modd;
b=b*fact[cntb[i]]%modd;
}
sort(s.begin(),s.end());
bool ok=true;
for(ll i=1;i<n;++i){
if(s[i-1].second>s[i].second){
ok=false;
break;
}
}
ll ab=0;
if(ok){
ab=1;
ll cnt=1;
for(ll i=1;i<n;++i){
if(s[i]==s[i-1]) cnt++;
else{
ab=ab*fact[cnt]%modd;
cnt=1;
}
}
ab=ab*fact[cnt]%modd;
}
ll ans=fact[n];
ans=(ans-a+modd)%modd;
ans=(ans-b+modd)%modd;
ans=(ans+ab)%modd;
cout<<ans;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll lll = 1;
// cin >> lll;
while (lll--) {
solve();
if (lll) cout << '\n';
}
return 0;
}
r7
A. Broken Keyboard
若某字符按键故障,则每次只能输出两个相同字符,因此该字符在字符串中的所有连续段长度必为偶数;
若出现奇数长度的连续段,则不可能由故障按键产生,说明该字符对应按键一定正常。
所以只要线性扫描字符串,按连续段统计长度,将出现过奇数段的字符加入答案并按字母序输出即可
B. Binary Palindromes
问题可以转换成给定一堆0和1,以及n个目标字符串长度,求解最多可以构造多少个回文串
偶数长度串需要len/2个字符
奇数长度串需要(len-1)/2个字符对和1个单字符(若单字符不够可以拆对补充)
同时为了使构造的数量最多,应从短到长、从偶到奇
C. Minimize The Integer
由于只能交换相邻且奇偶性不同的数字,因此奇数字符之间的相对顺序不变,偶数字符之间的相对顺序也不变,只有奇偶之间可以相互穿插
于是可以将原串按奇偶拆成两个子序列 odd 和 even,它们内部顺序固定
所以 问题转化为:在保持这两个子序列内部相对顺序不变的前提下,进行一次类似归并排序的合并,每次取当前较小的数字放入答案,从而得到字典序最小的整体序列,即为可构造的最小整数。
D. Salary Changing
题目目标是不超过预算s的前提下,使最终工资序列的中位数的中位数最大
(设k=(n+1)/2,中位数=排序后的第k个数)
等价于:能否让至少k个人的工资>=x
如果某个x可行,那么所有≤x的值必然可行,所以答案关于x具有单调性,所以可以用二分答案
check核心是判断当前这种方案能否是至少k人≥x且总花费≤s
实现逻辑:
1.先发最低工资(因为任何方案都要发l)
2.统计三种人:
l≥x:直接就满足,不用额外花钱
l<x≤r:需要补(x-l)
r<x:再怎么样也无法达到x,忽略
3.判断人数是否够了
1和2走完之后,判断在所有可升级的人全拉满的情况下,是否可以凑够k个人
不能 返回false
4.贪心策略去补钱
选补钱最少的k-直接满足人数 升级
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
#define modd 998244353
const ll N = 2e5+10;
static const ll INF = (ll)4e18;
bool check(ll x,const vector<pair<ll,ll>>&a,ll s,ll n){
ll k=(n+1)/2;
ll cost =0;
ll cnt=0;
vector<ll>need;
for(auto &[l,r]:a){
cost+=l;
if(l>=x) cnt++;
else if(r>=x) need.emplace_back(x-l);
}
if(cnt+(ll)need.size()<k) return false;
sort(need.begin(),need.end());
for(ll i=0;i<k-cnt;++i){
cost+=need[i];
}
return cost<=s;
}
void solve() {
ll n,s;cin>>n>>s;
vector<pair<ll,ll>>a(n);
for(ll i=0;i<n;++i){
cin>>a[i].first>>a[i].second;
}
ll L=1,R=1e18,ans=1;
while(L<=R){
ll mid=(L+R)>>1;
if(check(mid,a,s,n)){
ans=mid;
L=mid+1;
}else{
R=mid-1;
}
}
cout<<ans;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll lll = 1;
cin >> lll;
while (lll--) {
solve();
if (lll) cout << '\n';
}
return 0;
}
E1. Voting (Easy Version)
我觉得这题赛时能出的
没看到这题,放后面了。。
每个选民有两种方式被说服 花钱买票和群众压力
所以贪心策略先用最少的前去买一些选民,逐步扩大支持人数,触发连锁反应,最终覆盖所有人
代码实现:
始终维护当前支持“我”的人cur
把所有选民mi从小到大排序,用一个小根堆存储当前可购买的人的pi
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
#define modd 998244353
const ll N = 1e6+10;
static const ll INF = (ll)4e18;
ll fact[N];
struct node{
ll m,p;
}a[N];
priority_queue<ll,vector<ll>,greater<ll>>q;
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;cin>>n;
ll ans=0;
while(!q.empty()){
q.pop();
}
for(ll i=1;i<=n;++i) cin>>a[i].m>>a[i].p;
sort(a+1,a+1+n,cmp);
for(ll i=n;i>=1;i--){
q.push(a[i].p);
if(a[i].m>n-(ll)q.size()){
ans+=q.top();
q.pop();
}
}
cout<<ans;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll lll = 1;
cin >> lll;
while (lll--) {
solve();
if (lll) cout << '\n';
}
return 0;
}

浙公网安备 33010602011771号