A.Piling Up(思维)
题意:
在
A
t
C
o
d
e
r
AtCoder
AtCoder中,用户的评分以正整数形式给出,并根据该值显示一定数量的^
。具体来说,当评分介于
1
1
1和
399
399
399之间(含)时,显示规则如下:
- 当评级介于
1
1
1和
99
99
99(含)之间时,显示一次
^
。 - 当评级介于
100
100
100和
199
199
199(含)之间时,
^
会显示两次。 - 当评级介于
200
200
200和
299
299
299(含)之间时,
^
会显示三次。 - 当评级介于
300
300
300和
399
399
399(含)之间时,
^
会显示四次。
目前,高桥的评分是
R
R
R。这里可以保证
R
R
R是介于
1
1
1和
299
299
299之间的整数。
求他增加显示的^
所需的最小评分增幅。
可以证明,在这个问题的限制条件下,他可以增加^
的数量,而不需要将他的评分提高到
400
400
400或更高。
分析:
求某个数距离比它大的最近的一个 k × 100 k\times 100 k×100的距离是多少。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N=250005;
const int MOD=1000000007;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int R;
cin>>R;
int cnt=R/100;
cout<<(cnt+1)*100-R<<endl;
return 0;
}
B.Japanese Cursed Doll(排序)
题意:
有
N
N
N个人,第
i
i
i个
(
1
≤
i
≤
N
)
(1\leq i\leq N)
(1≤i≤N)人当前的头发长度是
L
i
L_i
Li。
每个人的头发每天增长
1
1
1。
请输出头发长度至少为
T
T
T的人数首次变为
P
P
P或更多的天数。
如果现在头发长度至少为
T
T
T的人数已经为
P
P
P或更多,则输出
0
0
0。
分析:
将 L L L从小往大排序,那么只需要第 n − P + 1 n−P+1 n−P+1大的数满足条件即可,假设这个数是 a a a。因此,只需要计算 T − a T−a T−a即可。
如果这个数是负数,意味着初始时就满足条件,此时要输出 0 0 0。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N=105;
const int MOD=1000000007;
int n,T,P;
int L[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>T>>P;
for(int i=1;i<=n;++i)
cin>>L[i];
sort(&L[1],&L[n+1]);
int l=L[n-P+1];
int ans=max(0,T-l);
cout<<ans<<endl;
return 0;
}
C.Avoid K Palindrome 2(字符串)
题意:
给你一个长度为 N N N的字符串 S S S,它只由小写英文字母组成。
求将 S S S的字符(包括字符串 S S S本身)置换后得到的字符串中,不包含长度为 K K K的回文字符串作为子串的字符串的个数。
这里,当且仅当存在一个不大于 ( N − K ) (N-K) (N−K)的非负整数 i i i,使得每个整数 j j j的 1 ≤ j ≤ K 1\leq j\leq K 1≤j≤K都有 T i + j = T i + K + 1 − j T_{i+j}=T_{i+K+1-j} Ti+j=Ti+K+1−j时,长度为 N N N的字符串 T T T才被称为 “包含长度为 K K K的回文字符串作为子串”。
这里, T k T_k Tk表示字符串 T T T的第 k k k个字符。
分析:
观察数据范围,直接枚举字符串 s s s的所有排列,然后暴力找有没有长度为 k k k的回文字符串即可。需要去重。
枚举字符串所有排列可以先给字符串排序,然后用next_permutation
找下一个排列。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N=105;
const int MOD=1000000007;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
LL n,k;
cin>>n>>k;
set<string>se;
string s;
cin>>s;
sort(s.begin(), s.end());
do{
LL ok=1;
for(int i=0,j=k-1;j<n;++i,++j) {
string tmp;
for(int p=i;p<=j;++p)
tmp+=s[p];
string we=tmp;
reverse(we.begin(),we.end());
if(we==tmp){
ok=0;
break;
}
}
if(ok)
se.insert(s);
}while(next_permutation(s.begin(),s.end()));
cout<<se.size()<<endl;
return 0;
}
D.Palindromic Number(数学)
题意:
如果一个非负整数
X
X
X的十进制表示(不含前导零)是一个回文数,那么这个非负整数
X
X
X就叫做回文数。
例如,
363
363
363、
12344321
12344321
12344321和
0
0
0都是回文数。
求第 N N N小的回文数。
分析:
因为是回文数,所以只需要考虑前一半就可以进行构造。
枚举长度,首先计算出答案回文数的长度。通过枚举和减法可以计算出是当前长度下第 k k k大的回文数。而前一半就是顺序的,第 k k k大就是当前长度的数的第 k k k大,这个很好求。接下来只需要构成回文,直接输出即可。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
LL N;
int a[1000];
LL fpow(LL a,LL b){
LL ret=1;
while(b){
if(b&1)
ret*=a;
a*=a;
b>>=1;
}
return ret;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>N;
N-=1;
if(N<10){
cout<<N<<endl;
return 0;
}
int l=1;
while(true){
int t=(l+1)>>1;
LL m=9ll*fpow(10,t-1);
if(N>m)
N-=m;
else
break;
++l;
}
int t=(l+1)>>1;
int len=0;
N-=1;
while(N){
a[++len]=N%10;
N/=10;
}
a[t]+=1;
for(int i=t;i;--i)
cout<<a[i];
for(int i=1+(l&1);i<=t;++i)
cout<<a[i];
cout<<endl;
return 0;
}
E.Sinking Land(搜索)
题意:
有一个面积为
H
×
W
H\times W
H×W的小岛,四面环海。
该岛被分成
H
H
H行和
W
W
W列的
1
×
1
1\times 1
1×1部分,从顶部起
i
i
i行和从左侧起
j
j
j列的部分(相对于当前海平面)的海拔高度为
A
i
,
j
A_{i,j}
Ai,j。
从现在开始,海平面每年上升
1
1
1。
在这里,垂直或水平临海的地段或沉入海中的地段,其标高不大于海平面,就会沉入海中。
在此,当一个断面新沉入海中时,任何垂直或水平相邻且标高不高于海平面的断面也将同时沉入海中,新沉入海中的断面重复这一过程。
对于每个 i = 1 , 2 , … , Y i=1,2,\ldots,Y i=1,2,…,Y,求 i i i年后该岛仍高于海平面的面积。
分析:
首先简单粗暴的考虑一下,对于每个海平面高度进行 b f s bfs bfs,在队列中找到不大于海平面的区域就拓展,并统计,计算一下发现此方法会TLE。
观察题目和数据,可以发现海平面为 a a a时沉没的区域,在海平面为 ( a + 1 ) (a+1) (a+1)时一定也会沉没。所以,不需要每次都重新 b f s bfs bfs,直接按着上一次的结果继续即可。同时我们还可以继续优化,找到不大于海平面的区域这一步,可以使用堆进行优化,一直取出当前堆内海拔最低的区域看是否被淹没,如果是就拓展,否则结束。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N=1005;
const int nx[4] = {1,0,-1,0};
const int ny[4] = {0,1,0,-1};
int h,w,y,a[N][N],t,ans;
struct Node{
int x,y,h;
bool operator < (const Node & a) const{
return a.h<h;
}
};
bool book[N][N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>h>>w>>y;
ans=h*w;
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++)
cin>>a[i][j];
priority_queue<Node> q;
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++)
if(i==1||j==1||i == h||j == w){
book[i][j]=1;
q.push({i,j,a[i][j]});
}
while(y--){
++t;
while(1 && !q.empty()){
Node now=q.top();
if(now.h<=t){
--ans;
q.pop();
for(int i=0;i<4;i++){
int tx=now.x+nx[i];
int ty=now.y+ny[i];
if(tx>=1 && tx<=h && ty>=1 && ty<=w && !book[tx][ty]){
q.push({tx,ty,a[tx][ty]});
book[tx][ty]=1;
}
}
}
else
break;
}
cout<<ans<<endl;
}
return 0;
}
赛后交流
在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。
群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。