0%

2020杭电多校-1补题

开始记录杭电多校补题了!

EASY

1004 Distinct Sub-palindromes

Distinct Sub-palindromes

题意

用x个字母来构建一个字符串,使得整个字符中回文子串最小,求构建数目

思路

当x为1、2、3时,将字符串构造成a,aa,aaa所成的回文子串数量最小,即为pow(26,n);
当x大于3时,字符串构造成abcabcabc……所成的回文子串即为3,即构造为262524种

AC 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n;
scanf("%d", &n);
while(n--){
int t;
cin >> t;
if(t==1)
cout << 26 << endl;
else if(t == 2)
cout << 676 << endl;
else if(t==3)
cout << 17576 << endl;
else
cout << 15600 << endl;
}
return 0;
}

1009 Leading Robots

Leading Robots

题意

给定n个机器人的初始位置和加速度,求有多少个机器人曾当过第一(并列第一不算第一)

思路

将数据的加速度按从小到大的顺序排序,若加速度相同则对初始位置的从小到大排序来处理,我们将数据进行记录,并记录位置和加速度的出现的个数,方便排除同一位置和加速度的机器人,如果后面的位置在前面位置的前面,则前面位置的机器人无法成为第一,若存在三个机器人的比较,则机器人B赶上A的时间大于等于C赶上B的则机器人B也无法成为第一,最后再处理可能存在的并列第一的

AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<stack>
using namespace std;
typedef long long ll;
#define maxn 50010
struct Node{
ll x,a;
}ro[maxn];

bool Judge(Node A,Node B,Node C){
return (B.x-C.x)*(B.a-A.a)-(C.a-B.a)*(A.x-B.x)<=0;//判断三者关系,如果B超过A的时间大于等于C 超过B的时间,则B无法担任第一
}
bool cmp(Node A,Node B){//排序
if(A.a!=B.a)return A.a<B.a;
else return A.x<B.x;
}
map<pair<ll,ll>,ll> mp;
ll n,top,Stack[maxn];
int main(){
ll t;
scanf("%lld",&t);
while(t--){
mp.clear();
scanf("%lld",&n);
for(ll i=0;i<n;i++){
scanf("%lld %lld",&ro[i].x,&ro[i].a);
pair<ll,ll> p;
p.first=ro[i].a;
p.second=ro[i].x;
mp[p]++;//如果同一位置同一加速度的机器人有多个,则这类机器人无法当第一
}
sort(ro,ro+n,cmp);
ll top=0;
for(ll i=0;i<n;i++){
while((top>0&&ro[i].x>=ro[Stack[top]].x)||(top>1&&Judge(ro[Stack[top-1]],ro[Stack[top]],ro[i]))){//后面位置在top前面,top无法当第一
top--;
}
Stack[++top]=i;
}
ll ans=top;
for(ll i=1;i<=top;i++){
pair<ll,ll> p;
p.first=ro[Stack[i]].a;
p.second=ro[Stack[i]].x;
if(mp[p]>1)ans--;
}
printf("%lld\n",ans);
}
return 0;
}

1011 Minimum Index

Minimum Index

题意

求每个前缀的字典序的最小后缀的位置,再求和

思路

Lyndon分解(对于字符串s,如果s的字典序严格小于s的所有后缀字符串,我们称s是简单串或Lyndon串,即分解出来的串si>=si+1)
对字符串s(d[i]表示前缀i的最小后缀的位置)分三种情况(s=s1s2s3使用i,j,k依次表示s2的起始位置,j表示s3的起始位置即新加入的字符,k表示j位字符在s2上一个循环节对应的字符):
1.当s[j]==s[k]时,意味着j对应的s2某个循环节的一个字符拼在s2
的末尾仍满足
2.s[j]>s[k],新的字符直接拼到s2末尾使之s2是一个Lyndon串
3.s[j] < s[k],可以继续在这个前缀后面增加s[k];

AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int d[1000010];
char s[1000010];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",s+1);
int ls=strlen(s+1);
long long cnt=0;
int i=1;
d[1]=1;
while(i<=ls)
{
int j=i;
int k=i+1;
while(k<=ls&&s[j]<=s[k])
{
if(s[j]<s[k])
{
d[k]=i;
j=i;
}
else
{
d[k]=d[j]+(k-j);
j++;
}
k++;
}
d[k]=k;
while(i<=j)
{
i+=k-j;
}
}
for(i=ls;i>=1;i--)
{
cnt=cnt*1112+d[i];
cnt%=1000000007;
}
printf("%lld\n",cnt);
}
return 0;
}

1012 Mow

题意

思路

AC代码