AGC 048 A~D
作者赛况:
Rank | Score | A | B | C | D |
---|---|---|---|---|---|
98 | 1700(-1)(86:11) | 300(9:05) | 700(40:24) | 700(-1)(81:11) | (-4) |
A
设t=“atcoder”
分以下几种情况讨论:
- s>t,则答案=0
- s[1] ≠ ′ a ′ \neq'a' =′a′,答案=1
- s[0]=s[1]=‘a’,则如果要使得s>t,必须要将某一个字符移动到s[0]或s[1]的位置,如果字符c
≠
′
a
′
\neq'a'
=′a′,可以移动到s[0],如果c>‘t’,可以移动到s[1]
O(n),找一下即可:
/*
{
######################
# Author #
# Gary #
# 2020 #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
int main(){
int t;
cin>>t;
while(t--){
string s;
cin>>s;
if(s>"atcoder"){
cout<<0<<endl;
}
else{
bool ok=1;
int rest=INF;
rb(i,1,s.length()-1){
if(s[i]!='a'){
ok=0;
check_min(rest,i);
if(s[i]>'t'){
check_min(rest,i-1);
}
}
}
if(ok){
cout<<-1<<endl;
}
else cout<<rest<<endl;
}
}
return 0;
}
/** 程序框架:
*
*
*
*
**/
B
即找出某些位置 i 1 , i 2 . . . i k i_1,i_2...i_k i1,i2...ik,使得 ∑ j = 1 k B i j − A i j \sum_{j=1}^k B_{i_j}-A_{i_j} ∑j=1kBij−Aij尽可能小。
那什么样的
i
i
i序列是合法的呢?
充要条件:对于所有的
[
]
[]
[]括号对,他们之间的位置个数为偶数。也就是如果
i
l
i_l
il放’[’,
i
r
i_r
ir放’]’,
i
l
≠
i
r
(
m
o
d
2
)
i_l\neq i_r(\mod 2)
il=ir(mod2)
则每一次我们可以从奇数位置取出一个最大的,偶数位置取出一个最大的,直到他们的和$\leq$0就行了。
/*
{
######################
# Author #
# Gary #
# 2020 #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
int n;
vector<int> v[2];
LL rest=0;
int a[100000+20],b[100000+20];
int main(){
cin>>n;
rb(i,1,n)
{
cin>>a[i];
rest+=a[i];
}
rb(i,1,n)
{
cin>>b[i];
v[i&1].PB(b[i]-a[i]);
}
sort(ALL(v[0]));
sort(ALL(v[1]));
LL MAX=0;
LL sum=0;
reverse(ALL(v[0]));
reverse(ALL(v[1]));
rep(i,n/2){
sum+=v[0][i]+v[1][i];
check_max(MAX,sum);
}
rest+=MAX;
cout<<rest<<endl;
return 0;
}
/** 程序框架:
*
*
*
*
**/
C
可以发现一个企鹅 i i i可以移动到的位置只可能是 A j + ( i − j ) A_j+(i-j) Aj+(i−j),所以只要随便处理一下就行了。
可以在脑子里想一想移动的过程。真的不太好描述。
推荐一个相当方的做法
/*
{
######################
# Author #
# Gary #
# 2020 #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
int n,L;
int a[100000+20],b[100000+20];
int nearl[100000+20],nearr[100000+20],l[100000+20],r[100000+20];
map<int,int> app;
int main(){
cin>>n>>L;
rb(i,2,n+1)
cin>>a[i];
rb(i,2,n+1)
cin>>b[i];
a[1]=b[1]=0;
a[n+2]=b[n+2]=L+1;
n+=2;
int delta=0;
rb(i,1,n){
delta++;
if(app[b[i]-delta]){
l[i]=app[b[i]-delta];
}
app[a[i]-delta]=i;
}
delta=0;
app.clear();
rl(i,n,1){
delta--;
if(app[b[i]-delta]){
r[i]=app[b[i]-delta];
}
app[a[i]-delta]=i;
}
rb(i,1,n){
nearl[i]=1;
if(b[i]==b[i-1]+1){
nearl[i]+=nearl[i-1];
}
}
rl(i,n,1){
nearr[i]=1;
if(b[i]==b[i+1]-1){
nearr[i]+=nearr[i+1];
}
}
LL rest=0;
rl(i,n,1){
if(b[i]==a[i]) continue;
if(l[i]==false&&r[i]==false){
cout<<"-1\n";
return 0;
}
if(l[i]){
assert(!r[i]);
rest+=i-l[i];
i-=min(i-l[i]-1,nearl[i]-1);
continue;
}
}
// cout<<rest<<endl;
rb(i,1,n){
if(b[i]==a[i]) continue;
if(r[i]){
assert(!l[i]);
rest+=r[i]-i;
i+=min(r[i]-i-1,nearr[i]-1);
continue;
}
}
cout<<rest<<endl;
return 0;
}
/** 程序框架:
*
*
*
*
**/
D
非常巧妙的dp。
赛场上我还以为有一个毒瘤的结论,猜了好多遍都过不了。。。
对于一段区间 [ l , r ] [l,r] [l,r],设先手是拿左边的,保证必胜, a l a_l al最小为 L e f t l , r Left_{l,r} Leftl,r,同理先手拿右边的, a r a_r ar最小为 R i g h t l , r Right_{l,r} Rightl,r
考虑转移 L e f t l , r Left_{l,r} Leftl,r。
若 l = r l=r l=r,则 L e f t l , r = 1 Left_{l,r}=1 Leftl,r=1
若 R i g h t l + 1 , r > a r Right_{l+1,r}>a_r Rightl+1,r>ar,则 L e f t l , r = 1 Left_{l,r}=1 Leftl,r=1。(直接拿完则必胜)
否则, a r ≥ R i g h t l + 1 , r , a_r\geq Right_{l+1,r}, ar≥Rightl+1,r,。
-
如果 a r a_r ar一旦 = R i g h t l + 1 , r =Right_{l+1,r} =Rightl+1,r,就必须一次拿完,不然变成 a r − 1 a_r-1 ar−1这时候 l l l拿完了最左边一堆, R i g h t Right Right就必败了。
-
如果 a r > R i g h t l + 1 , r a_r>Right_{l+1,r} ar>Rightl+1,r就与 L e f t Left Left互相消耗。这样可以在 a r a_r ar减少的同时减少 a l a_l al
-
当 a r > R i g h t l + 1 , r a_r>Right_{l+1,r} ar>Rightl+1,r时, L e f t Left Left也一定不会直接拿完,不然 R i g h t Right Right必胜,肯定也是一次拿一个。
-
在 a r = R i g h t l + 1 , r a_r=Right_{l+1,r} ar=Rightl+1,r的时候, a l a_l al一定已经消耗了 a r − R i g h t l + 1 , r + 1 a_r-Right_{l+1,r}+1 ar−Rightl+1,r+1个,这时候 a r a_r ar一次拿完, a l a_l al剩下的一定也要 ≥ L e f t l , r − 1 \geq Left_{l,r-1} ≥Leftl,r−1.
综上 L e f t l , r Left_{l,r} Leftl,r的转移为:
L
e
f
t
l
,
r
Left_{l,r}
Leftl,r
=
1
(
l
=
r
)
=1(l=r)
=1(l=r)
=
1
(
R
i
g
h
t
l
+
1
,
r
>
a
r
)
=1(Right_{l+1,r}>a_r)
=1(Rightl+1,r>ar)
=
a
r
−
R
i
g
h
t
l
+
1
,
r
+
1
+
L
e
f
t
l
,
r
−
1
(
a
r
≥
R
i
g
h
t
l
+
1
,
r
)
=a_r-Right_{l+1,r}+1+Left_{l,r-1}(a_r\geq Right_{l+1,r})
=ar−Rightl+1,r+1+Leftl,r−1(ar≥Rightl+1,r)
R
i
g
h
t
Right
Right的也与其类似,就不写了。
/*
{
######################
# Author #
# Gary #
# 2020 #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
#define left Left
#define right Right
#define int LL
/*}
*/
int N,a[101];
int left[101][101],right[101][101];
string s[2]={"Second","First"};
signed main(){
fastio;
int T;
cin>>T;
while(T--){
cin>>N;
rb(i,1,N)
cin>>a[i];
rb(len,1,N)
rb(i,1,N-len+1)
{
int j=i+len-1;
if(j==i){
left[i][j]=right[i][j]=1;
continue;
}
if(j==i+1){
left[i][j]=a[j]+1;
right[i][j]=a[i]+1;
continue;
}
if(left[i][j-1]>a[i]){
right[i][j]=1;
}
else{
right[i][j]=right[i+1][j]+(a[i]-left[i][j-1]+1);
}
if(right[i+1][j]>a[j]){
left[i][j]=1;
}
else{
left[i][j]=left[i][j-1]+(a[j]-right[i+1][j]+1);
}
}
cout<<s[(left[1][N]<=a[1])]<<endl;
}
return 0;
}
/** 程序框架:
*
*
*
*
**/
AGC真的太强了,前四题没有一题代码过50行。