A
直接按照题意模拟拿钥匙和开门即可……
$\texttt{Code}$
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;
void solve(){
string s;cin>>s;
int cntr=0,cntb=0,cntg=0;
rep(i,0,(int)s.size()-1){
if(s[i]=='r') cntr++;
if(s[i]=='g') cntg++;
if(s[i]=='b') cntb++;
if(s[i]=='R'){
if(!cntr){cout<<"NO\n";return;}
cntr--;
}
if(s[i]=='G'){
if(!cntg){cout<<"NO\n";return;}
cntg--;
}
if(s[i]=='B'){
if(!cntb){cout<<"NO\n";return;}
cntb--;
}
}cout<<"YES\n";
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;for(cin>>T;T--;)
solve();
return 0;
}
B
考虑 \(n\le 50\),范围非常小,于是可以用乱搞过。
当然可以考虑一个优美的构造,考虑倒序的排列一定是反斐波那契,然后题目要求构造 \(n\) 个,那我们考虑把这个序列旋转构成的序列刚好有 \(n\) 个,并且除了 \(n=3\) 以外都是合法的。而 \(n=3\) 就直接贺样例就行了。
$\texttt{Code}$
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;
void solve(){
int n;cin>>n;
if(n==3){
cout<<"3 2 1\n";
cout<<"1 3 2\n";
cout<<"3 1 2\n";
return;
}
per(i,n,1){
rep(j,0,n-1){
int cur=i-j;
if(cur<=0) cur+=n;
cout<<cur<<' ';
}cout<<'\n';
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;for(cin>>T;T--;)
solve();
return 0;
}
C
考虑记录长度为 \(len\) 的最大子段和是多少。然后贪心地,\(x\ge 0\),所以加上 \(x\) 一定不亏,于是枚举长度,然后每次在前面记录的最大和上加上 \(\min(len,k)*x\),取最大值就好了。这样预处理 \(O(n^2)\),单次求解 \(O(n)\),题目要求 \(k\in[0,n]\),那就 \(O(n^2)\)。
$\texttt{Code}$
#include<bits/stdc++.h>
#define int long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;
const int MAXN=5e3+10;
int mlen[MAXN],pre[MAXN];
void solve(){
int n,x,v;
cin>>n>>x;
rep(i,0,n) mlen[i]=-INF,pre[i]=0;
rep(i,1,n) cin>>v,pre[i]=pre[i-1]+v;
rep(i,1,n) rep(j,i,n)
mlen[j-i+1]=max(mlen[j-i+1],pre[j]-pre[i-1]);
rep(k,0,n){
int ans=0;
rep(i,1,n)
ans=max(ans,mlen[i]+min(i,k)*x);
cout<<ans<<' ';
}cout<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;for(cin>>T;T--;)
solve();
return 0;
}
D
$\texttt{Code}$
E
比 D 简单好多。考虑一个本质贪心,就是说你复制一定是把第一次出现的方向复制,因为你如果不复制第一次出现的,后面的可以用复制第一次出现的来代替。
于是整个的做法就是先求出最终的横纵坐标,这样可以求出 R
和 D
分别至多被复制多少次,然后从前往后扫,到一个位置,并记录前面有没有出现过 R
以及 D
,假如说下一步是向下走的,那么当前格子对最终答案贡献是向右走,否则贡献是向下走,然后判断一下贡献应该是 \(1\)(没有出现过向贡献方向走的字符)还是能向贡献方向复制的最多次数 \(+1\)。
$\texttt{Code}$
#include<bits/stdc++.h>
#define int long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;
void solve(){
int n;string s;cin>>n>>s;
int x=1,y=1,D=0,R=0;
rep(i,0,(int)s.size()-1){
if(s[i]=='D') x++,D=1;
if(s[i]=='R') y++,R=1;
}
D=(D?n-x+1:1);R=(R?n-y+1:1);
int ans=1;
bool aD=0,aR=0;
rep(i,0,(int)s.size()-2){
if(s[i]=='D') aD=1;
if(s[i]=='R') aR=1;
if(s[i+1]=='D'){
if(aR) ans+=R;
else ans++;
}
if(s[i+1]=='R'){
if(aD) ans+=D;
else ans++;
}
}
ans+=R*D;
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;for(cin>>T;T--;)
solve();
return 0;
}