A Split it!
思路:
翻转后看前k个连续是否相等,并且满足
k
∗
2
+
1
<
=
n
k*2+1 <= n
k∗2+1<=n
代码:
#include<bits/stdc++.h>
#include<iostream>
#include <stdio.h>
using namespace std;
const int maxn=200005;
const int base=131;
typedef long long ll;
#define pi acos(-1)
#define INF 0x3f3f3f3f
#define mod 998244353
const int inf=1<<30;
int a[maxn];
int b[maxn];
vector<int> pos;
int main()
{
//freopen("data.in","r",stdin);
//freopen("1.out","w",stdout);
int t,n,k;
cin>>t;
string s,s1;
while(t--){
cin>>n>>k;
cin>>s;
s1 = s;
reverse(s.begin(),s.end());
//cout<<s<<endl;
int f = 0,cnt = 0;
for(int i = 0;i < n ; i++ ){
if(s[i] != s1[i] ){
if(cnt >= k)
f = 1;
break;
}
cnt++;
if(cnt >= k){
f = 1;
break;
}
}
if(k == 0 || ( f && (k*2+1 <= n)))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
B Max and Mex
思路:可以用
a
+
b
+
1
2
\frac{a+b+1}{2}
2a+b+1计算
如果加入的这个b已经存在于序列中,mex和max不会变,答案为原序列中不同元素个数。
如果b不存在于序列中,并且原序列不是连续的,则有 m e x < m a x mex < max mex<max,那么b最小为 m e x + m e x + 1 + 1 2 \frac{mex +mex+1+1}{2} 2mex+mex+1+1,即 m e x + 1 mex+1 mex+1,加入后b后 m e x ′ mex' mex′和 m a x ′ max' max′不变,答案为原序列中不同元素个数加一。
如果b不存在于序列中,并且原序列是连续的则有
m
e
x
>
m
a
x
mex > max
mex>max,,mex一定为
m
a
x
+
1
max+1
max+1,那么b为
m
a
x
+
m
a
x
+
1
+
1
2
\frac{max +max+1+1}{2}
2max+max+1+1,即
m
a
x
+
1
max+1
max+1。
加入后b后,
m
e
x
′
mex'
mex′变为
m
e
x
+
1
=
m
a
x
+
2
mex+1= max +2
mex+1=max+2 ,
m
a
x
′
max'
max′变为
m
a
x
+
1
max+1
max+1,新的
b
′
=
b
+
1
=
m
a
x
+
2
b'=b+1=max+2
b′=b+1=max+2,以此类推……答案为原序列中不同元素个数加k。
代码:
#include<bits/stdc++.h>
#include<iostream>
#include <stdio.h>
using namespace std;
const int maxn=200005;
const int base=131;
typedef long long ll;
#define pi acos(-1)
#define INF 0x3f3f3f3f
#define mod 998244353
const int inf=1<<30;
ll a[maxn];
set<ll> vis;
int main()
{
//freopen("data.in","r",stdin);
//freopen("1.out","w",stdout);
ll t,n,k;
cin>>t;
string s,s1;
while(t--){
cin>>n>>k;
vis.clear();
memset(a,0,sizeof(a));
for(ll i = 1;i <= n;i++){
cin>>a[i];
vis.insert(a[i]);
}
sort(a+1,a+1+n);
ll aa,bb;
bb = a[n];
ll cnt = 0;
if(k == 0){
cout<<vis.size()<<endl;
continue;
}
ll i ;
for( i =1 ;i <= n;i++){
if(i == 1 && a[i] != 0)
{
aa = 0;
break;
}
if(a[i+1] != a[i]+1 ){
aa = a[i]+1;
break;
}
}
ll b = (aa + bb +1) / 2;
cnt++;
if(vis.find(b) != vis.end() || cnt == k){
vis.insert(b);
cout<<vis.size()<<endl;
}
else{ //找不到
if(aa > bb)
cout<<vis.size() + k<<endl;
else
cout<<vis.size() + 1<<endl;
}
}
return 0;
}
C Diamond Miner
思路:
将所有的x和y都映射到第一象限上,依次将最小的x点和y点一一对应求距离即可。
代码:
#include<bits/stdc++.h>
#include<iostream>
#include <stdio.h>
using namespace std;
const int maxn=200005;
const int base=131;
typedef long long ll;
#define pi acos(-1)
#define INF 0x3f3f3f3f
#define mod 998244353
const int inf=1<<30;
ll a[maxn],b[maxn];
int main()
{
//freopen("data.in","r",stdin);
//freopen("1.out","w",stdout);
ll t,n,k;
cin>>t;
while(t--){
cin>>n;
ll x ,y;
int cnt1 = 0,cnt2 = 0;
for(int i = 1;i <= n *2;i++){
cin>>x>>y;
if(x == 0){
if(y > 0)
a[++cnt1] = y;
else a[++cnt1] = -y;
}
if(y == 0){
if(x > 0)
b[++cnt2] = x;
else b[++cnt2] = -x;
}
}
sort(b+1,b+n+1);
sort(a+1,a+n+1);
double ans = 0.0;
for(int i =1;i <= n; i++){
ans += sqrt(a[i] * a[i]*1.0 + b[i] *b[i]*1.0);
}
printf("%.15lf\n",ans);
}
return 0;
}
D Let’s Go Hiking
题意:给定一个序列,Qingshan只能沿着单调下降的方向移动,Daniel只能沿着单调上升的方向移动,Q先移动,D后手,谁先不能移动谁输。
思路:
首先在这个n长的序列中可能有m个单调的连续子序列。Q和D都只能在单调子序列上移动,Q选择序列中最大的位置,D选择最小的位置。
为了让自己的移动步数多,Q和D都会选择最长的单调序列,因为如果让出最长的序列则必输。如果只有一个最长的单调序列,Q和D相当于往对方移动,必会相遇。由于Q先手,Q必输。
有多条等长的间隔开的单调序列,Q和D能移动的距离相等,因为Q先手,Q必输。
有连接在一起的等长单调序列时,即一个波形,单调上升和单调下降的部分长度相等为L。如果长度L为偶数,和上面的情况相同,Q必输。
如果每部分长度L为奇数,Q先手,Q可以往往两个方向移动。长度为奇数下Q和D相遇,Q先手D必输,所以D只能放在第二小的位置将这种相遇转化为长度为偶数的相遇;但是Q可以选择向另一边移动,Q和D同方向移动,Q还是可以L次,D放在第二小的位置只能移动L-1次,D必输。
代码:
#include<bits/stdc++.h>
#include<iostream>
#include <stdio.h>
using namespace std;
const int maxn=200005;
const int base=131;
typedef long long ll;
#define pi acos(-1)
#define INF 0x3f3f3f3f
#define mod 998244353
const int inf=1<<30;
int p[maxn];
int l[maxn],r[maxn];
int main()
{
//freopen("data.in","r",stdin);
//freopen("1.out","w",stdout);
int n;
cin>>n;
for(int i = 1; i <= n;i++){
cin>>p[i];
}
l[1] = 1;
r[n] = 1;
for(int i =2 ;i <= n;i++)
l[i] = (p[i] > p[i-1])? l[i-1] + 1 : 1;
for(int i = n-1 ;i >= 1; i--)
r[i] = (p[i] > p[i+1]) ? r[i+1] + 1 : 1;
int ma = 0,cnt = 0,vis = 0;
for(int i = 1;i <= n;i++){
if(l[i] > ma || r[i] > ma){
ma = max(l[i],r[i]);
cnt = 1;
vis = i;
}
else if(l[i] == ma || r[i] == ma){
cnt = 0;
}
}
int ans;
int mx = l[vis] > r[vis]? l[vis] : r[vis];
int mi = l[vis] > r[vis]? r[vis] : l[vis];
if(cnt && mx % 2 &&mx == mi)
ans = 1;
else
ans = 0;
cout<<ans<<endl;
return 0;
}
E Garden of the Sun
题意:
n行m列的农田里,种了n*m朵太阳花,因阳光猛烈太阳花死掉了许多,剩下的空格子没有共同边或角。
你需要移除剩下的太阳花,使得满足:一、空格是联通的,二、任何两个空格间都有一条简单路径,即所有的空格是不成环的。
思路:
构造,构的我心态炸了,就硬构。
每三行把其中一行全置空,行是三的倍数就置空中间的,不是置空第一行,然后联通剩下两行就可以了。
代码:
#include<bits/stdc++.h>
#include<iostream>
#include <stdio.h>
using namespace std;
const int maxn=60005;
const int base=131;
typedef long long ll;
#define pi acos(-1)
#define INF 0x3f3f3f3f
#define mod 998244353
const int inf=1<<30;
string g[maxn];
string ans[maxn];
int main()
{
//freopen("data.in","r",stdin);
//freopen("1.out","w",stdout);
// ios::sync_with_stdio(false); cin.tie(0);
int t,n,m;
cin>>t;
while(t--){
cin>>n>>m;
for(int i = 0; i < n; i++){
g[i].clear();
cin>>g[i];
}
for(int i = (n%3) == 0; i < n;){
for(int j = 0; j < m; j++)
g[i][j] = 'X';
i += 3;
if(i >= n)
break;
int pos = 1;
if(m == 1 || (g[i - 1][1] != 'X' && g[i - 2][1] != 'X' )){
pos = 0;
}
g[i - 1][pos] = 'X';
g[i - 2][pos] = 'X';
}
for(int i = 0; i < n; i++)
cout<<g[i]<<endl;
}
return 0;
}