在第一次CF第一題被叉與第二次CF第一題被FST掉的陰影下,報名參加了第三次的CF。。。心路歷程大概是這樣的:
開場后15min內:wocCF怎么上不上去?。。。算了到CF群里開始看起了T1題面,慌亂之中又看漏了T1中的正整數,成功掉了50分。。。
終於在21min過了T1,開始看T2
1min后:嗯這道題怎么好像很簡單啊。。。4min左右寫完,然后網卡,交不了。。。
然后大概在26min左右看起了T3:這道題不是傻逼DP嗎?寫完把細節改了改,35min左右過了所有樣例,然而。。。woc怎么還是交不了?
於是看起T4。。。到了41min,啊終於能交了,於是在41min同時過了T2與T3
剩下的2h-41min=1h19min:一直T4BFS不會寫,非要寫BFS套BFS還傻逼地以為寫的非常是正解,看到TLE后還加了一個類似分層圖的優化更加覺得是正解了,但這並不妨礙我從頭T到尾。。。
然后、、比賽結束,以rank1300多強勢墊底
認真地總結一下吧:CF每次都發揮不出水平,主要是因為CF的按時間減分的賽制讓我每次都非常緊張,迫切地想把每一題都迅速做完,然后每題就不敢多想,自然也就不能發揮出來了。所以既然考場上沒來得及想,就在考完試后再多想想吧。其次的話,自己水平還是不行吧,如果水平夠的話也不會那么緊張,所以還是需要多加訓練。話不多說,開始說題
A. Salem and Sticks
暴力枚舉,三種情況取個min即可
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
using namespace std;
const int N=1e3+10;
const int INF=1e9;
int n,a[N],t,ans=INF;
int main(){
scanf("%d",&n);
for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
for(register int p=1;p<=100;p++){
int sum=0;
for(register int i=1;i<=n;i++)
sum+=min(abs(a[i]-p),min(abs(a[i]-1-p),abs(a[i]+1-p)));
if(sum<ans)ans=sum,t=p;
}
printf("%d %d\n",t,ans);
return 0;
}
B. Zuhair and Strings
還是暴力枚舉
#include<cstdio>
#include<iostream>
using namespace std;
const int N=2e5+10;
int n,k,sum,ans,now;
char s[N];
int main(){
scanf("%d%d",&n,&k);
scanf("%s",s+1);
for(register int i=0;i<26;i++){
sum=now=0;
for(register int j=1;j<=n;j++){
if(s[j]==i+'a')now++;else now=0;
if(now==k)sum++,now=0;
}
ans=max(ans,sum);
}
printf("%d\n",ans);
return 0;
}
C. Ayoub and Lost Array
設\(dp[i][j]\)表示前 \(i\) 個數和在模 \(3\) 意義下為 \(j\) 的方案數,然后枚舉 \(l,r\) 轉移,復雜度 \(O(3n(r-l))\)
考慮把 \(l-r\) 中的數放在模 \(3\) 的剩余系下處理,這樣復雜度就只有 \(O(9n)\) 了
#include<cstdio>
#include<iostream>
using namespace std;
const int N=2e5+10;
const int mod=1e9+7;
int n,l,r,dp[N][3],num[3];
inline void Add(int &x,int y){x+=y;x-=x>=mod? mod:0;}
int main(){
scanf("%d%d%d",&n,&l,&r);
num[0]=r/3+1;
if(r-1>=0)num[1]=(r-1)/3+1;
if(r-2>=0)num[2]=(r-2)/3+1;
if(l-1>=0)num[0]-=max((l-1)/3+1,0);
if(l-2>=0)num[1]-=max((l-2)/3+1,0);
if(l-3>=0)num[2]-=max((l-3)/3+1,0);
dp[0][0]=1;
for(register int i=1;i<=n;i++)
for(register int j=0;j<3;j++)
for(register int p=0;p<3;p++)
Add(dp[i][j],1ll*dp[i-1][(j-p+3)%3]*num[p]%mod);
printf("%d\n",dp[n][0]);
return 0;
}
D. Kilani and the Game
也就是個簡單的BFS,注意訪問過的點直接打上vis標記不再訪問即可
同一種顏色的點同時BFS,不要每個單獨BFS(我當時就是這樣T掉的)
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=1e3+10;
const int M=20;
int n,m,p,s[N],head[M],cnt,num[N][N],ans[M];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool vis[N][N];
char mp[N][N];
struct peo{int nxt,x,y;}P[N*N];
struct node{int lef,x,y,col;node(int leff=0,int xx=0,int yy=0,int coll=0){lef=leff;x=xx;y=yy;col=coll;}};
queue<node>q;
inline void Add(int po,int x,int y){P[++cnt].nxt=head[po];P[cnt].x=x;P[cnt].y=y;head[po]=cnt;}
inline void exBFS(node k){
queue<node>nq;nq.push(k);
while(!q.empty()&&q.front().col==k.col)nq.push(q.front()),vis[q.front().x][q.front().y]=true,q.pop();
vis[k.x][k.y]=true;
while(!nq.empty()){
node u=nq.front();nq.pop();
for(register int i=0;i<4;i++){
int nx=u.x+dx[i],ny=u.y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&mp[nx][ny]!='#'&&(num[nx][ny]==0||num[nx][ny]==u.col)){
num[nx][ny]=u.col;
if(!vis[nx][ny]){
vis[nx][ny]=true;
if(u.lef>1)nq.push(node(u.lef-1,nx,ny,u.col));
else q.push(node(s[u.col],nx,ny,u.col));
}
}
}
}
}
inline void BFS(){
while(!q.empty()){node u=q.front();q.pop();exBFS(u);}
}
int main(){
scanf("%d%d%d",&n,&m,&p);
for(register int i=1;i<=p;i++)scanf("%d",&s[i]);
for(register int i=1;i<=n;i++)scanf("%s",mp[i]+1);
for(register int i=1;i<=n;i++)
for(register int j=1;j<=m;j++)
if(mp[i][j]!='#'&&mp[i][j]!='.')
Add(mp[i][j]-'0',i,j),num[i][j]=mp[i][j]-'0';
for(register int i=1;i<=p;i++)
for(register int j=head[i];j;j=P[j].nxt)
q.push(node(s[i],P[j].x,P[j].y,i)),vis[P[j].x][P[j].y]=true;
BFS();
for(register int i=1;i<=n;i++)
for(register int j=1;j<=m;j++)
ans[num[i][j]]++;
for(register int i=1;i<=p;i++)
printf("%d%c",ans[i],i==p? '\n':' ');
return 0;
}
E. Helping Hiasat
因為一個組中的人一定是相互排斥的,所以在一個組中的人中兩兩建邊,表示這兩個人不能同時選,然后建出來的圖的最大獨立集的點數就是最多的愉悅人數。
那么怎么求無向圖的最大獨立集呢?有一個性質:一個無向圖的最大獨立集等於這個無向圖補圖的最大團。
這個性質可以這么理解:對於原圖,如果兩個點之間有邊,那么在補圖中一定沒有這條邊,而最大團要求所選取的點集中的點兩兩都有邊相連,那么這兩個點就不可能同在補圖的最大團中,也就相應的不可能同在原圖的最大獨立集中了
然后最大團的話,多隨機幾下加點順序取個最大值就行了
#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<bitset>
#include<algorithm>
using namespace std;
const int N=50;
int n,m,k,store[N],a[N],tot,T=5e4;
bool Walk[N][N];
string s;
map<string,int>mp;
bitset<N>sav,ans;
inline void Process1(){
for(register int i=1;i<=store[0];i++)
for(register int j=i+1;j<=store[0];j++)
Walk[store[i]][store[j]]=Walk[store[j]][store[i]]=false;
memset(store,0,sizeof(store));
}
inline void Process2(){
if(!mp.count(s))mp[s]=++tot;
store[++store[0]]=mp[s];
}
int main(){
scanf("%d%d",&n,&m);scanf("%d",&k);n--;
memset(Walk,true,sizeof(Walk));
while(n--){
scanf("%d",&k);
if(k==1)Process1();
else cin>>s,Process2();
}
Process1();
for(register int i=1;i<=m;i++)a[i]=i;
while(T--){
random_shuffle(a+1,a+m+1);
for(register int i=1;i<=m;i++)sav[i]=1;
for(register int i=1;i<=m;i++)
if(sav[a[i]]==1)
for(register int j=i+1;j<=m;j++)
if(!Walk[a[i]][a[j]])sav[a[j]]=0;
if(sav.count()>ans.count())ans=sav;
}
printf("%d\n",ans.count());
return 0;
}
1月31號的codeforces再戰!(立flag:下次一定要到深藍)