概述
A
先判断
S
S
S 字典序是否大于atcoder
,是就输出
0
0
0。
否则往后面找到第一个不为a
的字母,移到第一位即可。假如这个字母字典序比t
还大,那么移到第二位就够了。
代码如下:
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 100010
int T,n;
char s[maxn];
char s2[9]={' ','a','t','c','o','d','e','r',0};
int main()
{
cin>>T;while(T--)
{
cin>>s+1;n=strlen(s+1);
int v=0;
for(int i=1;i<=min(n,7);i++){
if(s[i]>s2[i]){v=1;break;}
if(s[i]<s2[i]){v=-1;break;}
}
if(v==1||(!v&&n>7)){cout<<"0n";continue;}
int st=1;while(st<=n&&s[st]=='a')st++;
if(st>n)cout<<"-1n";
else{
if(st>1&&s[st]>'t')cout<<st-2<<"n";
else cout<<st-1<<"n";
}
}
}
B
先假设全部位置都用圆括号,然后考虑将一些位置变成方括号。
假设一对方括号的位置为 x , y x,y x,y,那么 y − x + 1 y-x+1 y−x+1 一定是偶数,即 x , y x,y x,y 的奇偶性一定不同。
然后可以发现,假如选出的变成方括号的位置集合为 X = { x 1 , x 2 , . . . , x k } X={x_1,x_2,...,x_k} X={x1,x2,...,xk},那么 X X X 内奇数和偶数各占一半。而奇数和偶数各占一半的集合,一定对应一个合法的括号序列。
一种简单的构造方案是:将
X
X
X 内的元素排序,每次找到一对相邻的并且奇偶性不同的
x
i
,
x
i
+
1
x_i,x_{i+1}
xi,xi+1(显然如果
X
X
X 不为空那么一定存在这样的一对数),将
[
x
i
,
x
i
+
1
]
[x_i,x_{i+1}]
[xi,xi+1] 区间的括号序列变成[()()...()()]
,内部已经被操作过的区间不变,然后将这一对数从
X
X
X 中删除。重复这个操作直到
X
X
X 为空,这样这个序列就造好了。
现在的问题是:选一些位置变成方括号,并且选出来的位置奇数和偶数各占一半。这个贪心即可,将 B i − A i B_i-A_i Bi−Ai 进行排序,奇数位和偶数位的分别排,然后每次选最大的两个,看看是否大于 0 0 0,是就选上。
代码如下:
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 100010
int n,a[maxn];
vector<int> b[2];
long long ans=0;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ans+=a[i];
}
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
b[i&1].push_back(x-a[i]);
}
for(int i=0;i<2;i++)sort(b[i].begin(),b[i].end());
for(int i=n/2-1;i>=0;i--){
int val=b[0][i]+b[1][i];
if(val<=0)break;
ans+=val;
}
printf("%lld",ans);
}
C
考虑相邻两只企鹅之间的空隙长度,记为 c i = A i + 1 − A i − 1 c_i=A_{i+1}-A_i-1 ci=Ai+1−Ai−1,那么企鹅的一次移动等价于使 j = i + 1 / i − 1 j=i+1/i-1 j=i+1/i−1,让 c j + = c i , c i : = 0 c_j+=c_i,c_i:=0 cj+=ci,ci:=0。
记 d i = B i + 1 − B i − 1 d_i=B_{i+1}-B_i-1 di=Bi+1−Bi−1,那么对于 d i > 0 d_i>0 di>0 的 i i i,这段空隙肯定等于 c c c 的一个区间 [ l , r ] [l,r] [l,r] 的和,对于 i > j i>j i>j 且 d i > 0 , d j > 0 d_i>0,d_j>0 di>0,dj>0,那么 j j j 对应的区间一定在 i i i 对应的区间前面。即对应的区间是有单调性的,并且这些区间不可能有交集,于是扫一遍就能得到这些区间。
而要将一个区间 [ l , r ] [l,r] [l,r] 的值全部累加到 i i i 位置,需要的操作次数为 max ( i − l , 0 ) + max ( r − i , 0 ) max(i-l,0)+max(r-i,0) max(i−l,0)+max(r−i,0),这个操作次数的总和就是答案,虽然需要考虑不同 i i i 之间操作的影响,但是由于区间有单调性,所以这个下限总是可以达到的,方案也不难构造。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 100010
int n,l,a[maxn],b[maxn],c[maxn],d[maxn];
long long ans=0;
int main()
{
scanf("%d %d",&n,&l);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);a[n+1]=l+1;
for(int i=1;i<=n;i++)scanf("%d",&b[i]);b[n+1]=l+1;
for(int i=0;i<=n;i++)c[i]=a[i+1]-a[i]-1;
for(int i=0;i<=n;i++)d[i]=b[i+1]-b[i]-1;
for(int i=0,j=0;i<=n;i++)if(d[i]){
while(c[j]==0)j++;
int l=j,s=0;
while(j<=n&&s<d[i])s+=c[j++];
if(s!=d[i])return printf("-1"),0;
ans+=max(i-l,0)+max(j-1-i,0);
}
printf("%lld",ans);
}
D
有一个性质:一个人每次要么拿一个,那么拿一堆,不可能拿 k ∈ ( 1 , a l ) kin(1,a_l) k∈(1,al) 个。如果拿了 k k k 个,那么下一次就只能拿 [ 1 , a l − k ] [1,a_l-k] [1,al−k] 个,如果拿 1 1 1 个,那么下一次可以拿 [ 1 , a l − 1 ] [1,a_l-1] [1,al−1] 个,显然后者的决策范围包含前者,所以前者一定不优。
然后考虑 dp text{dp} dp,设 l i , j l_{i,j} li,j 表示 两人只用 [ i , j ] [i,j] [i,j] 范围内的石子进行游戏,左方先手,且可以任意修改 a i a_i ai 的初值,则 a i a_i ai 至少为多少可以使左方必胜。
类似的,定义出 r i , j r_{i,j} ri,j:右方先手,则 a j a_j aj 至少为多少可以使右方必胜。
r r r 的转移和 l l l 类似,这里只说 l l l 的。
转移有两种:取一个或取一堆。如果 A j < r i + 1 , j A_j<r_{i+1,j} Aj<ri+1,j,那么左方直接取一堆,右方就变成了必败态,即左方无论 a i a_i ai 是多少都必胜,让 l i , j = 1 l_{i,j}=1 li,j=1。
否则,两个人肯定轮流一个一个取,直到某一方发现,自己取完之后对面必败,那么他就肯定会选择取完。
当左方取了
l
i
,
j
−
l
i
,
j
−
1
+
1
l_{i,j}-l_{i,j-1}+1
li,j−li,j−1+1 个时,右方直接取完,则右方胜利。当右方取了
a
j
−
r
i
+
1
,
j
+
1
a_j-r_{i+1,j}+1
aj−ri+1,j+1 个时,左方直接取完,则左方胜利。要使左方必胜,则需要满足:
l
i
,
j
−
l
i
,
j
−
1
+
1
>
a
j
−
r
i
+
1
,
j
+
1
l
i
,
j
>
a
j
−
r
i
+
1
,
j
+
l
i
,
j
−
1
l_{i,j}-l_{i,j-1}+1>a_j-r_{i+1,j}+1\ l_{i,j}>a_j-r_{i+1,j}+l_{i,j-1}
li,j−li,j−1+1>aj−ri+1,j+1li,j>aj−ri+1,j+li,j−1
所以 l i , j l_{i,j} li,j 的最小值为 a j − r i + 1 , j + l i , j − 1 + 1 a_j-r_{i+1,j}+l_{i,j-1}+1 aj−ri+1,j+li,j−1+1。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 110
#define ll long long
int T,n;
ll a[maxn];
ll l[maxn][maxn],r[maxn][maxn];
int main()
{
scanf("%d",&T);while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
l[i][i]=r[i][i]=1;
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
if(a[j]<r[i+1][j])l[i][j]=1;
else l[i][j]=a[j]-r[i+1][j]+l[i][j-1]+1;
if(a[i]<l[i][j-1])r[i][j]=1;
else r[i][j]=a[i]-l[i][j-1]+r[i+1][j]+1;
}
}
if(a[1]>=l[1][n])printf("Firstn");
else printf("Secondn");
}
}
最后
以上就是贪玩发卡为你收集整理的AGC048 部分题解的全部内容,希望文章能够帮你解决AGC048 部分题解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复