文章目录
A. How Much Does Daytona Cost?
题意:
给出一个长度为 n n n的序列 a a a和一个数字 k k k。请你判断 a a a中是否存在一个非空子段使得 k k k在这个子段中出现的次数严格大于其它数字的出现次数。存在输出 Y E S YES YES,否则输出 N O NO NO。
题解:
若序列中存在k,即为 y e s yes yes,否则为 n o no no。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#define int long long
using namespace std;
void solve(){
int n,k;
int flag=0;
cin>>n>>k;
for(int i=1;i<=n;i++){
int x;
cin>>x;
if(x==k) flag=1;
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
signed main(){
int t;
cin>>t;
while(t--) solve();
return 0;
}
B. Aleksa and Stack
题意:
每次构造一个数组,满足 ( 3 ∗ (3* (3∗a_{i+2} ) )%( )a_{i+1} + + +a_{i} ) ! = 0 )!=0 )!=0。
题解:
奇数 + 奇数 = 偶数 奇数+奇数=偶数 奇数+奇数=偶数, 奇数 ∗ 3 = 奇数 奇数*3=奇数 奇数∗3=奇数,奇数不能整除偶数,所以数组的构造方法就找到了。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2E5+10;
int a[N];
void solve(){
int n;
cin>>n;
a[1]=1;
a[2]=3;
for(int i=3;i<=n;i++) a[i]=a[i-1]+2;
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
}
int main(){
int t;
cin>>t;
while(t--) solve();
return 0;
}
C. Vasilije in Cacak
题意:
给定n,k,x,问能否从1~n中选出k个数,使其和为x。
题解:
求出最大能构成的数字,以及最小能构成的数字,若x在区间内就为yes,否则为no。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#define int long long
using namespace std;
const int N=2e5+10;
int a[N];
void solve(){
int n,k,x;
cin>>n>>k>>x;
int xiao=k*(k+1)/2;
int da=n*(n+1)/2-(n-k)*(n-k+1)/2;
if(x>=xiao&&x<=da) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
signed main(){
int t;
cin>>t;
while(t--) solve();
return 0;
}
D. Reverse Madness
题意:
给定一个长度为 n n n的仅包含小写拉丁字母的字符串 s s s,以及两个长度为 k k k的正整数序列 l l l, r r r,保证这两个序列满足:
- l 1 l_{1} l1 = 1 =1 =1;
- r k r_{k} rk = n =n =n;
- ∀ i ∈ [ 1 , k ] ∀i∈[1,k] ∀i∈[1,k], l i ≤ r i l_{i} ≤r_{i} li≤ri;
- ∀ i ∈ [ 2 , k ] ∀i∈[2,k] ∀i∈[2,k], l i = r i − 1 + 1 l_{i} =r_{i-1}+1 li=ri−1+1;
给定 q 次操作,每次给定一个正整数 x ( 1 ≤ x ≤ n ) x (1≤x≤n) x(1≤x≤n)。一次操作如下:
- 找到值 i i i 使得 l i ≤ x ≤ r i l_{i}≤x≤r_{i} li≤x≤ri(显然这样的 i 是唯一的)。
- 令 a = m i n ( x , r i + l i − x ) a=min(x,r_{i}+l_{i}-x) a=min(x,ri+li−x), b = m a x ( x , r i + l i − x ) b=max(x,r_{i}+l_{i}-x) b=max(x,ri+li−x),
- 翻转
s
a
,
b
s_{a,b}
sa,b。
输出 q q q次询问后的 s s s。
题解:
我们可以发现每个 [ l i , r i ] [l_{i},r_{i}] [li,ri],都是互不相交的区间,且每次修改都是对应的 [ l i , r i ] [l_{i},r_{i}] [li,ri]的一个子区间,且每个修改区间都是关于 ( l i + r i ) / 2 (l_{i}+r_{i})/2 (li+ri)/2对称,且不难看出对于一个区间 [ l , r ] [l,r] [l,r], x x x和 r − x + 1 r−x+1 r−x+1的修改是等价的。且最终的修改结果和顺序无关,只与每个点修改的次数有关,所以可以用一个数组存储当前点作为边界的修改次数,然后类似于前缀和的方式求出最终的 s s s。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N=2e5+10;
int a[N],b[N],cnt[N];
void solve(){
int n,k;
string s;
cin>>n>>k;
cin>>s;
for(int i=0;i<=n;i++) cnt[i]=0;
for(int i=0;i<k;i++) cin>>a[i],a[i]--;
for(int i=0;i<k;i++) cin>>b[i],b[i]--;
int q;
cin>>q;
for(int i=0;i<q;i++){
int x;
cin>>x;
cnt[x-1]++;
}
string ans="";
for(int i=0;i<k;i++){
int sum=0;
int l=a[i];
int r=b[i];
string s1=s.substr(a[i], b[i]-a[i]+1);
for(int j=l;j<=(l+r)/2;j++){
sum+=cnt[j]+cnt[r-j+l];
if(sum&1) swap(s1[j-l],s1[r-j]);
}
ans+=s1;
}
cout<<ans<<endl;
}
signed main(){
int t;
cin>>t;
while(t--) solve();
return 0;
}
E. Iva & Pav
题意:
每组数据给定长度为 q 次询问。我们定义 f(l,r)(1≤l≤r≤n) 表示 a l a_{l} al& a l + 1 a_{l+1} al+1& a l + 2 a_{l+2} al+2&… a r − 1 a_{r-1} ar−1& a r a_{r} ar的结果。其中,&表示位与运算。对于每次询问,将给定 l,k。请你找到最大的 r 使得 f(l,r)≥k。如果无解,输出 -1。
题解:
数组 b i , j b_{i,j} bi,j,表示前i个数的第j位1的数量,因为1&1才为1,所以只有当前i个数的第j位都为1时相与才为1,然后用二分查询r。
代码:
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N=2e5+10;
int a[N],b[N][33];
void solve(){
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<=n;i++)
for(int j=0;j<=33;j++) b[i][j]=0;
for(int i=0;i<n;i++)
for(int j=0;j<30;j++){
if(a[i]&(1<<j)) b[i+1][j]=b[i][j]+1;
else b[i+1][j]=b[i][j];
}
int q;
cin>>q;
while(q--){
int l,k;
cin>>l>>k;
if(a[l-1]<k){
cout<<"-1"<<endl;
continue;
}
int st=l,ed=n;
while(st<ed){
int mid=(st+ed+1)/2;
int sum=0;
for(int i=0;i<30;i++)
if(b[mid][i]-b[l-1][i]==mid-l+1) sum+=(1<<i);
if(sum<k) ed=mid-1;
else st=mid;
}
cout<<st<<endl;
}
}
signed main(){
int t;
cin>>t;
while(t--) solve();
return 0;
}