前言
传送门 :
阅读理解能力有待提高
A.
题意 :
给定一个字符串,
A
l
i
c
e
Alice
Alice和
B
o
b
Bob
Bob分别操作,
A
l
i
c
e
Alice
Alice先手询问是谁获胜并且输出得分
A
l
i
c
e
:
Alice :
Alice:能拿长度为偶数的子串
B
o
b
:
Bob:
Bob:能拿奇数的子串
得
分
:
得分:
得分:
a
=
1
,
b
=
2.....
a=1,b=2.....
a=1,b=2.....
思路 :
- 如果本串本来就是偶数,那么必然全拿
- 否则只让 B o b Bob Bob拿首或者尾两者之中的最小一个
第二种情况,因为题中说明不存在平手,因此必然成立,因为最坏情况 :
s
[
0
]
=
=
s
[
s
.
s
i
z
e
(
)
−
1
]
s[0]==s[s.size()-1]
s[0]==s[s.size()−1]但是因为不存在平手,也可以分出胜负
Code :
void solve(){
string s;cin>>s;
if(s.size() == 1){
cout<<"Bob"<<" "<<s[0]-'a'+1<<endl;
return;
}
int sum = 0 ;
for(auto x : s){
sum+=x-'a'+1;
}
//全拿
if(s.size()%2 == 0){
cout<<"Alice "<<sum<<endl;
return;
}
int minn = min(s[0],s[s.size()-1]);
minn = minn-'a'+1;
if(minn > sum - minn){
cout<<"Bob "<<minn - (sum - minn)<<endl;
return;
}
cout<<"Alice "<<sum-minn - minn <<endl;
}
B.
题意 :
给定一个字符串,对于任意一个三元组
(
t
,
u
,
v
)
,
t
∈
(
s
1
,
s
2
,
s
3..
)
,
(
u
,
v
)
∈
s
∣
c
n
t
u
−
c
n
t
v
∣
<
=
1
(t,u,v),t\in(s1,s2,s3..),(u,v)\in s \ |cnt_u - cnt_v |<=1
(t,u,v),t∈(s1,s2,s3..),(u,v)∈s ∣cntu−cntv∣<=1
即对于字符串的任意子串,都要满足字符串中任意两个字符,在该子串中的数量之差小于 1 1 1
思路 :
观察样例,我们可以知道,对于
a
b
a
aba
aba,
a
b
c
abc
abc,
a
a
a
a
a
aaaaa
aaaaa是成立的,同理我们再推几组
a
b
c
a
b
c
a
(
成
立
)
,
a
b
b
a
b
b
a
(
不
成
立
)
abcabca(成立),abbabba(不成立)
abcabca(成立),abbabba(不成立)
然后我们就会发现,两个连续之间要出现其他的所有字符,而连续的后面需要出现与前面相同的字符即构成一种
s
[
1
]
,
s
[
2
]
,
s
[
3
]
,
s
[
1
]
,
s
[
2
]
.
.
.
.
.
s[1],s[2],s[3],s[1],s[2].....
s[1],s[2],s[3],s[1],s[2].....这种类型
显然的,这是可以证明是正确的,因为对于 s [ 1 ] , s [ 2 ] , s [ 3 ] s[1],s[2],s[3] s[1],s[2],s[3]必然是满足条件的,而对于 s [ 1 ] , s [ 2 ] , s [ 3 ] , s [ 1 ] s[1],s[2],s[3],s[1] s[1],s[2],s[3],s[1]也是满足的,同理下去归纳一下,显然就是了
因此我们只需要找到前面单个出现的,然后判断 s [ i ] = = s [ i − p o s ] s[i] == s[i-pos] s[i]==s[i−pos]即可
Code :
void solve(){
mp.clear();
string s;cin>>s;
int len = s.size();
int pos = 0;
for(auto x : s){
if(mp[x])break;
pos++;
mp[x] = 1;
}
for(int i=pos;i<len;i++){
if(s[i]!=s[i-pos]){
cout<<"NO"<<endl;
return;
}
}
cout<<"YES"<<endl;
}
C.
题意 :
给定一个数,对其进行拆分,询问有多少种方法,但是要拆分成回文数的相加
(一开始我还以为这个回文数值的是被拆分出来之后如果存在 1 , 3 , 1 , 1 , 1 , 3 1,3,1\ ,1,1,3 1,3,1 ,1,1,3就是回文什么的,结果只是简单的回文
思路 :
因此显然是一个原题,900. 整数划分,我们可以通过完全背包将一个数拆分成
1..
n
1..n
1..n的和并且求其方案数,但是必须是回文,因此我们考虑先暴力求出所有回文,求出来只有
499
499
499个,因此是可行的,然后套一下板子即可了
Code :
// Problem: Palindrome Basis
// Contest: Codeforces
// URL: https://m1.codeforces.com/contest/1673/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <iostream>
#include <vector>
#include <map>
#include <cstring>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;
#define IOS ios::sync_with_stdio(false);
#define CIT cin.tie(0);
#define COT cout.tie(0);
#define ll long long
#define x first
#define y second
#define pb push_back
#define endl '\n'
#define all(x) (x).begin(),x.end()
#define Fup(i,a,b) for(int i=a;i<=b;i++)
#define Fde(i,a,b) for(int i=a;i>=b;i--)
typedef priority_queue<int,vector<int>,greater<int>> Pri_m;
typedef pair<int,int> pii;
typedef vector<int> VI;
map<int,int> mp;
const int N = 4e4+10,mod = 1e9+7;
ll f[N];
int hw[N],idx;
bool check(int x){
int tt[6] = {0};
int cnt = 0 ;
while(x){
tt[++cnt] = x%10;
x/=10;
}
for(int i=1, j = cnt; i<=j;i ++ , j -- ){
if(tt[i]!=tt[j])return false;
}
return true;
}
void init(){
for(int i=1;i<=9;i++) hw[++idx] = i;
for(int i=10;i<=N;i++){
if(check(i)) hw[++idx] = i ;
}
}
void solve_init(){
// int n;cin>>n;
// for(int i=1;i<=n;i++) f[i] = 0 ;
f[0] = 1;
for(int i=1;i<=idx;i++){
for(int j=hw[i];j<=N;j++){
f[j] = (f[j]%mod + f[j-hw[i]]%mod)%mod;
}
}
// cout<<f[n]%mod<<endl;
}
void solve(){
int n;cin>>n;
cout<<f[n]%mod<<endl;
}
int main(){
IOS
CIT
COT
init();
solve_init();
// cout<<idx<<endl;
int t;cin>>t;while(t--)
solve();
return 0 ;
}