「模拟赛」暑期集训CSP提高模拟15(8.7)
1.「模拟赛」高一下三调5.13(附关于二分图匈牙利建边的详细思考)2.模拟赛3.「模拟赛」CSP提高组模拟1(7.14)4.「模拟赛」暑期集训CSP提高模拟5(7.22)5.「模拟赛」暑期集训CSP提高模拟4(7.21)6.「模拟赛」暑期集训CSP提高模拟3(7.20)7.「模拟赛」暑期集训CSP提高模拟2(7.19)8.CSP 集训(9.23-9.26)9.「模拟赛」暑期集训CSP提高模拟17(8.10)
10.「模拟赛」暑期集训CSP提高模拟15(8.7)
11.「模拟赛」暑期集训CSP提高模拟14(8.6)12.「模拟赛」暑期集训CSP提高模拟11(7.29)13.「模拟赛」暑期集训CSP提高模拟10(7.28)14.joke 学长出题比赛记录15.「模拟赛」暑期集训CSP提高模拟6(7.23)16.CSP 联训 217.CSP 联训 318.「模拟赛」多校 A 层联训 8(更新 T3)19.「模拟赛」CSP-S 模拟 11(T2 超详细)20.「模拟赛」多校 A 层联训 521.「模拟赛」多校 A 层联训 4(卖品:CTH)22.【小 w 的代数】(打什么 n^3,提供一种 n log 的解法)23.「模拟赛」多校 A 层联训 9赛时记录:
开场看 T1,一眼
看 T2,发现结论题,推了会结论打上走了。
打完 T2 想了会 T3、T4,无思路,回来打了 T1 暴力和特殊性质,
之后去打了 T3 暴力,以及 T4 暴力(但 T4 打一半就结束了)。
总分
T1 我的所谓正解只拿了
T2 也是细节写错了。
A.串串 38pts
自己赛时手推的
不是,怎么我自己打的
这是赛时自己打的 manacher
void manacher(){
int tail = 0, whi = 0;
for(int mid=2; mid<=n-1; mid++){
if(tail > mid){
int con = whi - (mid - whi);
if(f[con] + mid < tail) f[mid] = f[con];
else{
f[mid] = tail - mid;
for(int len=1; len<=min(n-tail, mid-f[mid]-1); len++){
if(s[tail+len] != s[mid-(tail-mid)-len]) {f[mid] += len - 1;break;}
if(len == min(n-tail, mid-f[mid]-1)) f[mid] += len;
}
}
}
else{
for(int len=1; len<=min(n-mid, mid-1); len++){
if(s[len+mid] != s[mid-len]) {f[mid] = len - 1; break;}
if(len == min(n-mid, mid-1)) f[mid] = len;
}
}
if(f[mid] and tail < mid+f[mid])
tail = mid + f[mid], whi = mid;
// cout<<mid<<": "<<f[mid]<<"\n";
}
}
这是博客园粘的板子
int manacher()
{
int len=init();
int ans=-N,id,mx=0;
for(int i=1;i<len;i++)
{
if(i<mx)p[i]=min(p[id*2-i],mx-i);
else p[i]=1;
while(news[i-p[i]]==news[i+p[i]])p[i]++;
if(mx<i+p[i])id=i,mx=i+p[i];
ans=max(ans,p[i]-1);
}
return ans;
}
正解:
-
manacher 求每一个位置为回文中心的最长回文子串;
-
哈希 求每一个回文串的长度。
两个方法都是为了求出所有回文子串。
然后枚举每个回文子串,
- 如果这个子串末尾是整个串的最末位,那么这个串是合法的(直接以末位翻转可以形成原串);
- 如果这个子串是从整个串最首位开始的,且它也可作为另一个合法发回文子串的前半段,那么这个子串也合法。(翻转之后形成的串还可以再翻转直到形成原串)
code:
#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define love cout<<"---------\n";
using namespace std;
const int N = 1e6 + 10;
int T, n, f[N], can[N];
char s[N];
void manacher(){
int tail = 0, whi = 0;
for(int mid=2; mid<=n-1; mid++){
if(tail > mid){
int con = whi - (mid - whi);
if(f[con] + mid < tail) f[mid] = f[con];
else{
f[mid] = tail - mid;
for(int len=1; len<=min(n-tail, mid-f[mid]-1); len++){
if(s[tail+len] != s[mid-(tail-mid)-len]) {f[mid] += len - 1;break;}
if(len == min(n-tail, mid-f[mid]-1)) f[mid] += len;
}
}
}
else{
// cout<<s[1+mid]<<" "<<s[mid-1]<<" ";
for(int len=1; len<=min(n-mid, mid-1); len++){
if(s[len+mid] != s[mid-len]) {f[mid] = len - 1; break;}
if(len == min(n-mid, mid-1)) f[mid] = len;
}
}
if(f[mid] and tail < mid+f[mid])
tail = mid + f[mid], whi = mid;
// cout<<mid<<": "<<f[mid]<<"\n";
}
can[n] = true;
for(int i=n-1; i>=2; i--){
if(f[i]+i == n) can[i] = true;
else if(can[f[i]+i] and i-f[i]==1) can[i] = true;
}
for(int i=2; i<=n; i++){
if(can[i]) cout<<i<<" ";
}cout<<"\n";
}
int main(){
// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin>>T;
while(T--)
{
cin>>(s+1); n = strlen(s+1);
if(n == 1){cout<<1<<"\n";continue;}
manacher();
for(int i=1; i<=n; i++) f[i] = can[i] = 0;
}
return 0;
}
B.排排
结论推的没问题,但是判一个位置
题面:
正解:
只有 0 ~ 3 四个答案:
-
序列本来就是有序的,答案为 0;
-
存在一个位置
保证 并且 之前出现了 区间内的所有数时,答案为 1;(只在 位操作一次即可) -
1 在
位上, 在 1 位上时,答案为3;(先看答案为 2 的情况。此时的情况我们可以随便在不是 1 和 的位置操作一次使得出现答案为 2 的情况再按答案为 2 的情况操作两次) -
其余答案为2;(
不在第 1 位上时,我们在第 1 位操作一次,使得 可以到第 位;再在 上操作一次即可。若 1 不在 位上,一样)
code :
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 2e5 + 10;
int T, n, a[N];
int head[N], tail[N];
int main(){
// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin>>T;
while(T--)
{
cin>>n;
bool f0 = true;
for(int i=1; i<=n; i++){
cin>>a[i];
if(a[i] != i) f0 = false;
head[i] = false;
}
if(f0){cout<<"0\n";continue;}
if(a[1] == n and a[n] == 1){cout<<"3\n"; continue;}
int h = a[1], t = a[1] - 1;
for(int i=2; i<=n; i++){
if(a[i] < h) t--;
else if(a[i] > h + 1) t += a[i] - h - 1;
h = max(a[i], h);
if(!t) head[i] = true;
}
int w = a[n]; t = n - a[n];
for(int i=n-1; i>=1; i--){
if(a[i] > w) t--;
else if(a[i] < w - 1) t += w - 1 - a[i];
w = min(w, a[i]);
if(!t and head[i]){
t = -180; break;
}
}
if(t == -180){cout<<"1\n"; continue;}
if(a[1] == 1 or a[n] == n){cout<<"1\n"; continue;}
cout<<"2\n";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】