【简要题解】Educational Codeforces Round 123 简要题解
老年选手打着玩。
Doors and Keys
有一个长度为6的串,由
rgbRGB
各出现一次组成。小写代表钥匙,大写代表门,问你是否可以走到6
直接模拟就好,然而我tmd看错题了写了个搜索还在想现在CF educational round的第一题怎么这么难了。
#include<bits/stdc++.h>
using namespace std;
int qr(){
int ret=0,c=getchar(),f=0;
while(!isdigit(c)) f=c==45,c=getchar();
while( isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
char s[15];
int flg;
void dfs(int l,int r,int dep,int R,int G,int B){
//fprintf(stderr,"%d %d %d %d %d %d\n",l,r,dep,R,G,B);
if(R<0||G<0||B<0) return;
if(l==1&&r==6) return flg=1,void();
if(dep>15||flg) return;
while(islower(s[r+1])){
R+=s[r+1]=='r';
G+=s[r+1]=='g';
B+=s[r+1]=='b';
++r;
}
while(islower(s[l-1])){
R+=s[l-1]=='r';
G+=s[l-1]=='g';
B+=s[l-1]=='b';
--l;
}
if(isupper(s[l-1])) dfs(l-1,r,dep+1,R-(s[l-1]=='R'),G-(s[l-1]=='G'),B-(s[l-1]=='B'));
if(isupper(s[r+1])) dfs(l,r+1,dep+1,R-(s[r+1]=='R'),G-(s[r+1]=='G'),B-(s[r+1]=='B'));
}
int main(){
int T=qr();
while(T--){
flg=0;
scanf("%s",s+1);
for(int t=1;t<=1;++t)
if(islower(s[t]))
dfs(t,t,0,s[t]=='r',s[t]=='g',s[t]=='b');
if(flg) puts("YES");
else puts("NO");
}
return 0;
}
Anti-Fibonacci Permutation
一个排列是反斐波那契的,当且仅当\(\forall i \ge 3,p_{i-1}+p_{i-2}\not = p_i\),对于一个\(n\),请你输出\(n\)个反斐波那契排列
排列小于\(10\)先搜索一下然后打表。
排列大于\(10\)考虑把\(1\quad 2\quad 3\)换成\(3\quad 1 \quad 2\),然后对于排列最后\(5\)个数进行next_permutation
,一定可以搞出很多出来,选出其中\(n\)个即可,复杂度\(O(5!n)\)
#include<bits/stdc++.h>
using namespace std;
int qr(){
int ret=0,c=getchar(),f=0;
while(!isdigit(c)) f=c==45,c=getchar();
while( isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=150;
int a[maxn];
string ans[]={"","","","1 3 2 \n2 3 1 \n3 1 2 \n","1 2 4 3 \n1 3 2 4 \n1 4 2 3 \n1 4 3 2 \n","1 2 4 3 5 \n1 2 4 5 3 \n1 2 5 3 4 \n1 2 5 4 3 \n1 3 2 4 5 \n","1 2 4 3 5 6 \n1 2 4 3 6 5 \n1 2 4 5 3 6 \n1 2 4 5 6 3 \n1 2 5 3 4 6 \n1 2 5 3 6 4 \n","1 2 4 3 5 6 7 \n1 2 4 3 5 7 6 \n1 2 4 3 6 5 7 \n1 2 4 3 6 7 5 \n1 2 4 5 3 6 7 \n1 2 4 5 3 7 6 \n1 2 4 5 6 3 7 \n","1 2 4 3 5 6 7 8 \n1 2 4 3 5 6 8 7 \n1 2 4 3 5 7 6 8 \n1 2 4 3 5 7 8 6 \n1 2 4 3 6 5 7 8 \n1 2 4 3 6 5 8 7 \n1 2 4 3 6 7 5 8 \n1 2 4 3 6 7 8 5 \n","1 2 4 3 5 6 7 8 9 \n1 2 4 3 5 6 7 9 8 \n1 2 4 3 5 6 8 7 9 \n1 2 4 3 5 6 8 9 7 \n1 2 4 3 5 6 9 7 8 \n1 2 4 3 5 6 9 8 7 \n1 2 4 3 5 7 6 8 9 \n1 2 4 3 5 7 6 9 8 \n1 2 4 3 5 7 8 6 9 \n","1 2 4 3 5 6 7 8 9 10 \n1 2 4 3 5 6 7 8 10 9 \n1 2 4 3 5 6 7 9 8 10 \n1 2 4 3 5 6 7 9 10 8 \n1 2 4 3 5 6 7 10 8 9 \n1 2 4 3 5 6 7 10 9 8 \n1 2 4 3 5 6 8 7 9 10 \n1 2 4 3 5 6 8 7 10 9 \n1 2 4 3 5 6 8 9 7 10 \n1 2 4 3 5 6 8 9 10 7 \n"};
int main(){
int T=qr();
while(T--){
int n=qr();
if(n<=10) printf("%s",ans[n].c_str());
else{
for(int t=1;t<=n;++t) a[t]=t;
a[1]=3; a[2]=1; a[3]=2;
int cnt=0;
do{
int flg=1;
for(int t=3;t<=n;++t)
if(a[t-2]+a[t-1]==a[t])
flg=0,t=n;
if(flg){
++cnt;
for(int t=1;t<=n;++t)
printf("%d ",a[t]);
putchar('\n');
}
}while(next_permutation(a+n-5+1,a+n+1)&&cnt<n);
if(cnt!=n){
//cerr<<"qwq";
return 0;
}
}
}
return 0;
}
Increase Subarray Sums
给定一个序列和一个数\(x\),设\(f(k)\)表示选取序列中\(k\)个数加上\(x\)然后求出的最大子段和。输出\(f(0)\dots f(n)\)
设\(Max[i]\)表示长度为\(i\)的子段中的最大子段和,然后\(f(k)=\max(Max[i]+\min(i,k)\times x)\),复杂度\(O(n^2)\)
#include<bits/stdc++.h>
using namespace std;
int qr(){
int ret=0,c=getchar(),f=0;
while(!isdigit(c)) f=c==45,c=getchar();
while( isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
typedef long long ll;
const int maxn=5005;
int a[maxn];
ll Max[maxn];
int main(){
int T=qr();
while(T--){
ll n=qr(),x=qr();
for(int t=1;t<=n;++t) a[t]=qr();
for(int t=1;t<=n;++t) Max[t]=-1e12;
for(int t=1;t<=n;++t){
int s=0;
for(int i=t;i<=n;++i){
s+=a[i];
Max[i-t+1]=max<ll>(Max[i-t+1],s);
}
}
for(int k=0;k<=n;++k){
ll ans=0;
for(int i=0;i<=n;++i)
ans=max<ll>(ans,min(k,i)*x+Max[i]);
printf("%lld ",ans);
}
putchar('\n');
}
return 0;
}
Cross Coloring
有一个\(n\times m\)的格子图,初始是白色。你要进行\(q\)次操作,每次操作你要选择\(k\)种(k种都不是白色)颜色中一个颜色,然后\(x_i\)行和\(y_i\)列就被染上这个颜色。问染色方案数。
答案\(=\)(在最终染色方案中有用的染色操作)\(^k\)。
考虑一个操作\(i\)是没用的(即被其他染色操作完全覆盖了),当且仅当
-
对于某个行,\(j>i,x_j=x_i\) 或者 在之后所有列都被染过一次颜色。
-
对于某个列,\(j>i,y_j=y_i\) 或者 在之后所有行都被染过一次颜色了。
复杂度\(O(n)\)
#include<bits/stdc++.h>
using namespace std;
int qr(){
int ret=0,c=getchar(),f=0;
while(!isdigit(c)) f=c==45,c=getchar();
while( isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=2e5+5;
const int mod=998244353;
typedef long long ll;
int ksm(const int&ba,const int&p){
int ret=1;
for(int t=p,b=ba;t;t>>=1,b=1ll*b*b%mod)
if(t&1) ret=1ll*ret*b%mod;
return ret;
}
int row[maxn],col[maxn];
pair<int,int> que[maxn];
int main(){
int T=qr();
while(T--){
int n=qr(),m=qr(),k=qr(),Q=qr(),fcnt=Q,cntr=0,cntc=0;
for(int t=1;t<=n;++t) row[t]=0;
for(int t=1;t<=m;++t) col[t]=0;
for(int t=1;t<=Q;++t) que[t].first=qr(),que[t].second=qr();
for(int t=Q;t;--t){
int cnt=0;
if(row[que[t].first]||cntc==m) ++cnt;
if(!row[que[t].first]) row[que[t].first]=t,++cntr;
if(col[que[t].second]||cntr==n) ++cnt;
if(!col[que[t].second]) col[que[t].second]=t,++cntc;
if(cnt==2) --fcnt;
}
int ans=ksm(k,fcnt);
printf("%d\n",ans);
}
return 0;
}
Expand the Path
有一个机器人,遵循
DR
规则,即遇到一个D
就往下走一格,遇到一个R
就往右走一格。现在初始给你一个DR
串,你每次可以选择任何一个字母,比如D
,把他变成DD
。问你可以经过多少格?一个格子可以被经过,当且仅当存在一种操作该DR
串的方式,使得机器人在不走出地图的情况下经过这个格子。
考虑那些走不到的格子,是原DR
串走出的轮廓线下方或者右方,模拟一下即可。(有事待会再详细更博,未完待续)
#include<bits/stdc++.h>
using namespace std;
int qr(){
int ret=0,c=getchar(),f=0;
while(!isdigit(c)) f=c==45,c=getchar();
while( isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
typedef long long ll;
const int maxn=2e5+5;
char s[maxn];
int main(){
int T=qr();
while(T--){
int n=qr();
scanf("%s",s+1);
int L=strlen(s+1);
int flg=1;
for(int t=2;t<=L;++t)
if(s[t]!=s[t-1])
flg=0;
if(flg){
printf("%d\n",n);
continue;
}
ll ans=1ll*n*n,sav=0,lastcnt=0;
for(int t=L;t;--t){
if(s[t]=='D') ++sav,lastcnt=0;
if(s[t]=='R') ans-=sav,++lastcnt;
}
if(s[1]=='R') ans-=(n-1-sav)*lastcnt;
sav=0;
for(int t=L;t;--t){
if(s[t]=='R') ++sav,lastcnt=0;
if(s[t]=='D') ans-=sav,++lastcnt;
}
if(s[1]=='D') ans-=(n-1-sav)*lastcnt;
printf("%lld\n",ans);
for(int t=1;t<=L;++t) s[t]=0;
}
return 0;
}