传送门:CF
A题:A. Love Story
简单比对一下即可解决
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int main() {
int T=read();
while(T--) {
string s="codeforces";
string k;cin>>k;
int ans=0;
for(int i=0;i<s.length();i++) {
if(s[i]!=k[i]) ans++;
}
cout<<ans<<endl;
}
return 0;
}
B题:Blank Space
记录最大的连续0的个数,循环模拟即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];
int main() {
int T=read();
while(T--) {
int n=read();
for(int i=1;i<=n;i++) {
a[i]=read();
}
int maxx=0;int len=0;
for(int i=1;i<=n;i++) {
if(a[i]==0) {
len++;
}
else {
maxx=max(maxx,len);
len=0;
}
}
maxx=max(maxx,len);
cout<<maxx<<endl;
}
return 0;
}
C题:Mr. Perfectly Fine
字符串或运算之后存在"11".考虑记录"01""11""10"各自的最小花费,那么最终的答案就是min(“01”+“10”,“11”).直接输出即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int main() {
int T=read();
while(T--) {
int n=read();
int min1=int_INF,min2=int_INF,min3=int_INF;
for(int i=1;i<=n;i++) {
int num=read();string s;cin>>s;
if(s=="00") continue;
else if(s=="01") min1=min(min1,num);
else if(s=="11") min2=min(min2,num);
else if(s=="10") min3=min(min3,num);
}
if(min(min1+min3,min2)>=int_INF) cout<<-1<<endl;
else cout<<min(min1+min3,min2)<<endl;
}
return 0;
}
D题:Gold Rush
容易看出每一次操作就是得到
n
/
3
,
n
∗
2
/
3
n/3,n*2/3
n/3,n∗2/3.问最后是否能得到m.考虑倒过来思考,就是对
m
m
m进行反操作,每次得到
m
∗
3
,
m
∗
1.5
m*3,m*1.5
m∗3,m∗1.5问最后是否能得到
n
n
n
考虑使用map的性质来进行死循环式的枚举.因为map是自带从小到大排序的,并且我们每一次进行乘法显然也是单调增的.所以恰好可以利用这个性质.只要我们最终的map中出现n,那么显然是直接输出"Yes".但是此时我们的遍历时死循环的.所以我们需要考虑一下边界.显然当我们当前枚举到的值大于
n
n
n的时候便没必要继续下去了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
map<int,int>mp;
int main() {
int T=read();
while(T--) {
int n=read(),m=read();
mp.clear();
int minn=m;mp[m]=1;
for(auto it : mp) {
mp[it.first*3]=1;
minn=max(it.first,minn);
if(it.first*3%2==0) {
mp[it.first*3/2]=1;
minn=max(it.first*3/2,minn);
}
if(mp[n]) {
cout<<"YES"<<endl;
break;
}
if(minn>n) {
cout<<"NO"<<endl;
break;
}
}
}
return 0;
}
E题:The Lakes
简单染色题.对于每一个联通块进行染色并且累计一下贡献即可.在本题中使用
d
f
s
dfs
dfs并不会爆栈,所以直接使用
d
f
s
dfs
dfs即可
假设不会染色题,建议直接搜索一下对应的知识,网上对此有大量的介绍,此处就不在赘述了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int mp[2000][2000];
int vis[2000][2000];
int dx[4]={1,0,-1,0};
int dy[4]={0,-1,0,1};
int n,m;int sum=0;
void dfs(int x,int y) {
for(int i=0;i<4;i++) {
int nx=x+dx[i],ny=y+dy[i];
if(nx<1||nx>n||ny<1||ny>m||mp[nx][ny]==0||vis[nx][ny]) continue;
vis[nx][ny]=1;
sum+=mp[nx][ny];
dfs(nx,ny);
}
}
int main() {
int T=read();
while(T--) {
n=read(),m=read();
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
mp[i][j]=read();
vis[i][j]=0;
}
}
int ans=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(!vis[i][j]&&mp[i][j]!=0) {
vis[i][j]=1;
sum=mp[i][j];
dfs(i,j);
ans=max(ans,sum);
}
}
}
cout<<ans<<endl;
}
return 0;
}
F题:Forever Winter
发现最终的只有边界的雪花顶点的入度是唯一的(考虑存无向边,那么入度等于出度的),并且入度只能是1.所以从这个开始入手.
先存下每一个点的入度.那么找到入度为1的点,这个点就是边界的那个点.这个点有一个唯一的邻接点(记为u),不难发现
i
n
[
u
]
−
1
in[u]-1
in[u]−1就是我们其中的一个答案.并且我们还会发现对于u的所有邻接点v中,只有当v为雪花的顶点时入度是不等于1的.所以我们不难找到雪花的顶点.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int in[maxn];
vector<int>edge[maxn];
int main() {
int T=read();
while(T--) {
int n=read(),m=read();
for(int i=1;i<=n;i++) {
edge[i].clear();
in[i]=0;
}
for(int i=1;i<=m;i++) {
int u=read(),v=read();
edge[u].push_back(v);
edge[v].push_back(u);
in[u]++;in[v]++;
}
int ans1=0,ans2=0;
for(int i=1;i<=n;i++) {
if(in[i]==1) {
ans1=in[edge[i][0]]-1;
int u=edge[i][0];
for(int j=0;j<edge[u].size();j++) {
int v=edge[u][j];
if(in[v]!=1) {
ans2=in[v];
}
}
break;
}
}
cout<<ans2<<" "<<ans1<<endl;
}
return 0;
}
G题:G. Hits Different
本题我是纯纯的使用数列的递推的方法解决的.应该是属于较麻烦的那一类.
不难发现,当我们的数字是可以由之前的数字递推而来的.更为详细的来说:
我们的当前的数字的贡献可以由他的正上方的两个数字进行递推而来,举个栗子:
当前数字等于8:此时我们由4和5递推而来
当前数字等于7,此时因为7处于边界状态,所以有一个数字不存在,那么就直接由4递推而来
但是此时需要注意的是,我们的
F
(
8
)
!
=
F
(
4
)
+
F
(
5
)
+
8
∗
8
F(8)!=F(4)+F(5)+8*8
F(8)!=F(4)+F(5)+8∗8,我们此时发现会存在重复,并且不难发现此时重复的值就是
F
(
2
)
F(2)
F(2)(也就是跨一行的正上方).
那么对于每一个点,我们都找到对应的递推点以及重复点即可(具体方法此处就不在赘述了,找起来也并不麻烦,可以参考代码)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define int long long
#define maxn 1000010
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int num[maxn];
signed main() {
int T=read();
num[1]=1;int cnt=1;int len=1;
for(int i=2;i<=1e6+10;i++) {
if(cnt==1) num[i]=i*i+num[i-len];
else if(cnt==len+1) num[i]=i*i+num[i-len-1];
else {
num[i]=i*i+num[i-(len+1)]+num[i-(len+1)+1];
int k=i-(len+1);
if(cnt-1==1) num[i]-=num[k-(len-1)];
else {
num[i]-=num[k-(len)+1];
}
}
cnt++;
if(cnt>len+1) cnt=1,len++;
}
while(T--) {
int n=read();
cout<<num[n]<<endl;
}
return 0;
}
H题:Don’t Blame Me
发现我们的最终的状态很小.并且我们最后需要的是每一个状态的贡献.所以在实现的过程中显然可以枚举每一个贡献.刚开始我想的方案是可以记录每一个数字在我们最终序列中的贡献(考虑拆位记录,使用组合数统计)(这个想法很符合CF的出题尿性),但是真正实现过程中感觉很麻烦.然后赛时队友提出了
d
p
dp
dp的想法.感觉很对.
考虑使用
d
p
[
i
]
[
s
]
dp[i][s]
dp[i][s]来记录前
i
i
i位可以形成最终状态为
s
s
s的子序列个数.不难发现递推方式:
当前数字可以选择使用或者不使用:
1.如果不使用,那么对之前的状态没有影响,此时
d
p
[
i
]
[
s
]
+
=
d
p
[
i
−
1
]
[
s
]
dp[i][s]+=dp[i-1][s]
dp[i][s]+=dp[i−1][s]
2.如果考虑使用,那么此时我们可以对之前所有存在的
s
s
s进行
a
n
d
and
and运算,也就是
d
p
[
i
]
[
s
&
a
[
i
]
]
+
=
d
p
[
i
−
1
]
[
s
]
dp[i][s\&a[i]]+=dp[i-1][s]
dp[i][s&a[i]]+=dp[i−1][s]
最后只要每一个符合的状态
s
s
s然后累加贡献即可(本题若想到计数dp,则并不难实现)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define int long long
const int mod=1e9+7;
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];
int dp[200010][1<<7];
signed main() {
int T=read();
while(T--) {
int n=read(),k=read();
for(int i=1;i<=n;i++) {
a[i]=read();
}
for(int i=1;i<=n;i++) {
for(int s=0;s<(1<<6);s++) {
dp[i][s]=0;
}
}
dp[1][a[1]]=1;
for(int i=2;i<=n;i++) {
dp[i][a[i]]=(dp[i][a[i]]+1)%mod;
for(int s=0;s<(1<<6);s++) {
dp[i][s]=(dp[i][s]+dp[i-1][s])%mod;
dp[i][s&a[i]]=(dp[i][s&a[i]]+dp[i-1][s])%mod;
}
}
int ans=0;
for(int s=0;s<(1<<6);s++) {
int temp=s;int cnt=0;
while(temp) {
cnt+=temp%2;
temp/=2;
}
if(cnt==k) {
ans=(ans+dp[n][s])%mod;
}
}
cout<<ans<<endl;
}
return 0;
}
今日迷思:
曾经不只有一次想过算法竞赛这个东西到底有没有意义,自从接触这个算法竞赛以来,我花了初三的时间,花了高中三年的时间,现在到了大学,还在苦逼的坚持.说真的,为了打算法竞赛真的感觉自己失去了很多.高中一起相约大学打ACM的同学也感觉慢慢的在淡出,他们上各类OJ的时间间隔越来越长,有时候不禁真的在想:还有必要继续坚持下去吗.
但是这场比赛的H题,我最后是在赛后一分钟实现了AC代码,当时时间处于凌晨一点钟,我只能说这种紧张,懊悔+快乐的混杂情感可能是我不打算法竞赛永远体会不到的.可能这就是继续坚持下去的意义吧.不是为了成绩,不是为了别人,而是为了那短暂的快乐.
希望之后的自己会感谢现在充满了负面情绪在悬崖边坚持的自己.