牛客周赛 Round 97
A. 回文串
点击查看代码
#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(){
char a,b,c;
cin>>a>>b>>c;
if(a==b || a==c || b==c){
cout<<"YES";
}
else cout<<"NO";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
return 0;
}
B. 2025
点击查看代码
#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,val=1;
cin>>n;
while(n){
int tmp=n%10;
n/=10;
val*=tmp;
}
// cout<<val<<endl;
for(int i=0;i<=1000000;i++){
if(i*i==val){
cout<<"YES";
return;
}
}
cout<<"NO\n";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
return 0;
}
数据范围n和q是2e5, 如果每次询问都o(n)的做一遍,复杂度是4e10, 不可接受
考虑对每次询问如何 o(1) 的计算答案
每次询问的x,y中,中间需要跳过的障碍物距离,即为x后面第一个障碍物的位置,到y前面第一个障碍物的位置 的距离
所以,可以预先用前后缀和维护出,每个位置,前一个和后一个障碍物的位置,这样在每次询问时,就可以o(1)的得到答案
代码实现中还需要考虑x,y中间没有障碍物的情况
点击查看代码
#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,q;
cin>>n>>q;
string s;
cin>>s;
s=" "+s;
vector<int> pre(n+10),suf(n+10,n+1);
for(int i=1;i<=n;i++){
pre[i]=pre[i-1];//当前位置前最近的障碍物
if(s[i]=='#') pre[i]=i;
}
for(int i=n;i>=1;i--){
suf[i]=suf[i+1];
if(s[i]=='#') suf[i]=i;
}
while(q--){
int a,b;
cin>>a>>b;
int x=min(a,b),y=max(a,b);
if(suf[x]>y || pre[y]<x){
cout<<0<<endl;
continue;
}
cout<<pre[y]-suf[x]+1<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
return 0;
}
D. 字符串操作
因为要让字典序尽可能大,所以样让从前往后每个位置都尽可能大
所以先找到第一个不是 z 的位置,让这个位置右移 cnt 次,变成 z。
这个位置就是选中的子字符串开始的位置,同时右移次数也确定为 cnt 次
从这个位置的下一个开始,让每个位置都右移 cnt 次,直到某个位置,右移 cnt 次后反而变小,则变小位置的上一个位置就是子字符串的结束位置
点击查看代码
#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;
string s;
cin>>s;
s=" "+s;
vector<int> a(n+10);
int pos=0;
for(int i=1;i<=n;i++){
a[i]=s[i]-'a';
if(a[i]!=25 && pos==0){
pos=i;
}
}
if(pos==0){
for(int i=1;i<=n;i++){
cout<<s[i];
}
return;
}
int cnt=25-a[pos];
for(int i=pos;i<=n;i++){
if(a[i]+cnt>25) break;
a[i]+=cnt;
}
for(int i=1;i<=n;i++){
cout<<(char)('a'+a[i]);
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
return 0;
}
E. 平衡排列
首先考虑不存在的情况,当 1-n 的和为奇数时,一定不存在平衡序列
此时 1-n 的和为偶数,一定存在平衡序列,假设 1-n 的和是sum
我们需要构造一个排列,同时找到一个位置,让小于等于这个位置的和等于 sum/2 ,此时大于这个位置的和也等于sum/2
所以只考虑构造排列的前半部分即可
我们需要的数是 need = sum/2, 从n到1循环i,只要need大于等于当前的i,就把need放进排列的前半部分,同时让need -= i
当need小于当前的i时,直接把当前的need放进排列的前半部分
此时再把 1-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;
int sum=(1+n)*n/2;
if(sum&1){
cout<<-1<<endl;
return;
}
map<int,int> used;
vector<int> ans;
sum/=2;
for(int i=n;i>=1;i--){
if(sum>=i){
ans.push_back(i);
used[i]=1;
sum-=i;
}
else{
if(sum>0){
ans.push_back(sum);
used[sum]=1;
}
break;
}
}
for(int i=1;i<=n;i++){
if(!used[i]) ans.push_back(i);
}
for(auto val:ans){
cout<<val<<" ";
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
return 0;
}
F. 小苯的序列分段
只需要考虑,bi 和 bi+1 之间,有cnt个位置可以分割,再把每个cnt乘起来即可
分别考虑 bi 和 bi+1 在区间 bi 到 bi+1 中可以分割的位置
用单调栈处理出,每个位置后面第一个比它大的位置 ri,和每个位置前面第一个比它大的位置 li
bi 和 bi+1 的cnt即为区间 bi 到 bi+1 中,ri 和 li+1 的交集
例如:
3 1 2 4 5, b是3,5
则ri是位置4(对应的数是4,注意要和bi+1的位置取min,因为分割的位置不能大于li的位置),li+1是位置0,因为5是最大的,但是此时li+1要和bi的位置取max(因为分割的位置不能小于bi的位置)
还需要特判第一个b的前面有没有比第一个b大的,最后一个b后面还有没有比最后一个b小的
点击查看代码
#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;
cin>>n>>m;
vector<int> a(n+1),b(m+1);
map<int,int> pos;
for(int i=1;i<=n;i++){
cin>>a[i];
pos[a[i]]=i;
}
for(int i=1;i<=m;i++){
cin>>b[i];
b[i]=pos[b[i]];
}
vector<int> r(n+1,n+1),l(n+1,0);//r:右边最近的比他大的数的位置
vector<int> stk;
for(int i=n;i>=1;i--){
while(stk.size() && a[stk.back()]<a[i]){
stk.pop_back();
}
if(stk.size()){
r[i]=stk.back();
}
stk.push_back(i);
}
stk.clear();
for(int i=1;i<=n;i++){
while(stk.size() && a[stk.back()]<a[i]){
stk.pop_back();
}
if(stk.size()){
l[i]=stk.back();
}
stk.push_back(i);
}
for(int i=1;i<=m;i++){
if(i!=m) r[b[i]]=min(r[b[i]],b[i+1]);
if(i!=1) l[b[i]]=max(l[b[i]],b[i-1]);
}
int ans=1;
for(int i=1;i<m;i++){
ans*=max(0ll,r[b[i]]-l[b[i+1]]);
ans%=mod;
}
if(l[b[1]]!=0 || r[b[m]]!=n+1){
ans=0;
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
return 0;
}

浙公网安备 33010602011771号