比赛链接:Dashboard - Codeforces Global Round 25 - Codeforces

A

题意:有 $n$ 栈灯从 $1-n$ 排成一排,初始时全是熄灭状态,每次只能选择两盏不相邻的熄灭的灯将其点亮,问能否达到一种给定的状态。

将最终状态中点亮的灯分成前后两半,每次分别在两半中选一盏灯。注意特判。

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
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
char s[55];
cin>>s;
int num=0;
for(int i=0;i<n;i++)
{
if(s[i]=='1')num++;
}
if(num%2==1)
{
cout<<"NO\n";
continue;
}
int p=0;
bool flag=1;
for(int i=0;i<n;i++)
{
if(s[i]=='1')
{
p++;
}
if(p==num/2 )
{
if(num==2&&s[i+1]=='1')
flag=0;
break;
}
}
if(flag)cout<<"YES\n";
else cout<<"NO\n";
}
}

B

题意:有 $n$ 头牛比赛,每头牛有个能力值,从头到尾两两比赛,赢家和下一个比较,输的淘汰。现在排在第 $k$ 位的牛可以选择和任一个位置的牛交换,求这头牛能赢的比赛的最大数目。

首先考虑直接把第 $k$ 头牛放在第一个位置的答案是多少,再考虑将其和 $k$ 之前最大的牛交换的答案是多少,比较即可。

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
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n,k;
cin>>n>>k;
int a[n+5];
for(int i=1;i<=n;i++)cin>>a[i];
bool flag=0;
int ans=-1;
for(int i=1;i<k;i++)
{
if(a[i]>a[k])
{
ans=i-2;

swap(a[i],a[k]);
k=i;

flag=1;
break;
}
}
if(!flag)
{
swap(a[k],a[1]);
k=1;
}

int num;
if(k==1)num=0;
else num=1;
for(int i=k+1;i<=n;i++)
{
if(a[i]<a[k])num++;
else break;
}
cout<<max(ans,num)<<endl;
}
}

C

有一家公司卖票一共 $n$ 天,每一天的单价是 $a_i$ ,现在需要采购 $k$ 张票,每天买的票的最大数量不能超过 $m$ ,而且若在某一天买了 $x$ 张票,那么以后每一天的单价都会增加 $x$ 。求最小代价。

假设买一天买 $b_i$ 张,那么一共的消费就是
$$
\sum(a_i+\sum b_j)b_i=\sum a_ib_i+\sum_{1\leq j<i\leq n}b_ib_j
$$
可得最后的结构与 $a$ 的顺序无关,那么如下贪心:将 $a_i$ 从小到大排序,依次每一个 $b_i$ 都分配 $m$ ,最后一个分配 $k%m$ 。易得到前项这样是最大的,那么对于第二项,有:
$$
\sum_{1\leq j<i\leq n}b_ib_j=\frac{1}{2}(\sum b_i)^2-\frac{1}{2}(\sum b_i^2)
$$
此时 $\frac{1}{2}(\sum b_i)^2$ 是定值,而要使 $\frac{1}{2}(\sum b_i^2)$ 最大,就要使每个 $b_i$ 尽可能一样,与贪心策略符合。

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
#include<bits/stdc++.h>
using namespace std;
#define int long long

void solve()
{
int n,m,k;
cin>>n>>m>>k;
int a[n+5];
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
int ans=0;
int tot=0;
for(int i=1;i<=n;i++)
{
if(tot+m<=k)
{
tot+=m;
ans+=m*a[i];
}
else
{
ans+=(k-tot)*a[i];
break;
}
}
ans+=m*m*(k/m)*(k/m-1)/2+(k-k/m*m)*(k/m)*m;
cout<<ans<<endl;
}

signed main()
{
int t;
cin>>t;
while(t--)solve();
return 0;
}

math


D

题意:有一个人买东西,有 $n$ 元钱,而且他来到一个摊子就会尽最大可能买下能买的东西。现需要你摆出不超过60个摊子,每个摊子物品无限,但价格相同,使得这个人在依次光顾每个摊子后恰好买 $k$ 件东西。

若 $k=n$ ,那么只需要一个卖价为1的摊子即可。

其他情况,考虑只摆两个摊子(很多这种构造题都是构造极少的数据即可通过),第一个摊子只买一个,第二个摊子设卖价为1,因此需满足:
$$
n/(n-k+1)=1,\ n-k+1>k-1
$$
即若满足
$$
2k<n+1
$$
则一定可以构造。

若不满足这个条件,即需要买的物品超过了钱的一半,那么每个摊子的价格不能超过2,经简单验证显然不成立。

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
#include<bits/stdc++.h>
using namespace std;

void solve()
{
long long n,k;
cin>>n>>k;
if(k==n)
{
cout<<"YES\n1\n1\n";
return ;
}
if(k>n)
{
cout<<"NO\n";
return ;
}
if(2*k>=n+2)
{
cout<<"NO\n";
return ;
}
cout<<"YES\n2\n"<<n-k+1<<" "<<1<<endl;
}

int main()
{
int t;
cin>>t;
while(t--)solve();
return 0;
}

math


E

题意:给出一个串 $s$ ,找出一种划分,使得将其划分成多个子串后每个子串都不是回文串。

若 $s$ 本来就不是回文,那么直接输出即可。

其他情况,考虑最多划分成两个串:枚举分界点,若依次分割两个段都不是回文那么满足条件。用manacher判断是否是回文。

若以任意一个位置划分都不满足条件,可以证明那么这个串一定不存在合法划分。

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
54
55
56
57
58
59
60
61
62
63
#include<bits/stdc++.h>
using namespace std;

vector<int> manacher(string s)
{
string t;
for(auto c:s)
{
t+=string("#")+c;
}
t+=string("#");
int n=t.length();
vector<int>p(n+2);
t="$"+t+"%";

int l=1,r=1;
for(int i=1;i<=n;i++)
{
p[i]=max((int)0,min(r-i,p[l+r-i]));

while(t[i+p[i]+1]==t[i-p[i]-1])p[i]++;
if(i+p[i]>r)
{
r=i+p[i];
l=i-p[i];
}
}
return vector<int>(begin(p)+2,end(p)-2);
}

void solve()
{
string s;
cin>>s;
int n=s.length();
vector<int>f=manacher(s);
if(f[n-1]!=n)
{
cout<<"YES\n1\n"<<s<<'\n';
return ;
}
bool flag=0;
for(int i=0;i<n-1;i++)
{
if(f[i]<i && f[i*2+1+n-1-i]<n-1-i)
{
cout<<"YES\n2\n";
for(int j=0;j<=i;j++)cout<<s[j];cout<<" ";
for(int j=i+1;j<n;j++)cout<<s[j];cout<<endl;
return ;
}
}
cout<<"NO\n";
return ;
}

int main()
{
int t;
cin>>t;
while(t--)solve();
return 0;
}

strings