Atcoder Beginner Contest 449

A:3,2,1,GO

直接按题意输出即可。

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;

signed main()
{
cin>>n;
for(int i=n;i>=1;i--)
{
if(i!=1) cout<<i<<",";
else cout<<i;
}
return 0;
}

B:Split Ticketing

输入的时候注意不要输入i = 0的情况,随后按题意枚举即可(记得从西向东,因此吃了罚时)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=102;
int n;
int a[maxn][maxn];
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
if(i==j) continue;
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
for(int k=j+1;k<=n;k++)
{
if((a[i][j]+a[j][k])<a[i][k]) { cout<<"Yes"; return 0; }
}
}
}
cout<<"No";
return 0;
}

C:Puddles

显然本题使用BFS最方便。BFS扩展去寻找每个连通块,若寻找到有在边上的连通块便打上tag。最终答案便是连通块数-打tag数。注意特判只有一个在边上的点的情况。赛时实现略为复杂。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1002;
int a[maxn][maxn],judge[maxn][maxn],tag[maxn*maxn];
int h,w,num;
char c;
struct nodd{
int x,y;
};
int x[10]={1,0,-1,0};
int y[10]={0,1,0,-1};
void getans(nodd pos)
{
queue<nodd> q;
q.push(pos);
while(!q.empty())
{
nodd now=q.front(); q.pop();
for(int i=0;i<=3;i++)
{
int tox=now.x+x[i];
int toy=now.y+y[i];
if((tox<1)||(tox>h)||(toy<1)||(toy>w)) continue;
if((a[tox][toy]==0)&&(judge[tox][toy]==0))
{
if((tox==1)||(toy==1)||(tox==h)||(toy==w)) tag[num]=1;
q.push(nodd{tox,toy}); judge[tox][toy]=1;
}
}
}
}
signed main()
{
cin>>h>>w;
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
{
cin>>c;
if(c=='#') a[i][j]=1;
else a[i][j]=0;
}
}
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
{
if(judge[i][j]==0 && a[i][j]==0)
{
judge[i][j]=1; num++;
getans(nodd{i,j});
if(i==1||i==h||j==1||j==w) tag[num]=1;
}
}
}
int len=num;
for(int i=1;i<=len;i++) if(tag[i]==1) num--;
cout<<num;
return 0;
}

D:Minimize Range

体感是一道比较简单的D。首先对数组中每个值取模,然后排序。取模的原因就是我们想让处理后的最大值-最小值最小,所以就无脑先都加到对k取模之后的结果就行。随后我们对数组排序,如果不进行处理答案就是an − a1,我们想怎么让极差更小,其实对每个数字来说只可能加一次k,因为多加没有意义;而且只有从小到大连续都加k才有意义,比如说对a1, a3两个数都加k,显然不如a1, a2两个数都加k来的好。这样我们从1n − 1依次枚举所有同时加k的区间,极差就是ai + k − ai + 1,我们可以在这个过程中维护极差的最小值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=300002;
int n,k;
int a[maxn];
signed main()
{
cin>>n>>k;
for(int i=1;i<=n;i++) { cin>>a[i]; a[i]%=k; }
sort(a+1,a+1+n);
int minn=a[n]-a[1];
for(int i=1;i<=n-1;i++) minn=min(minn,(a[i]+k)-a[i+1]);
cout<<minn;
return 0;
}

E:Fibonacci String

赛时做了不短时间,感觉很容易被绕进去。首先看到1e18的下标就知道要找结论了。观察可知,由于对于n > 2,有S[i] = s[i − 1] + s[i − 2],我们可以发现S[i − 1]永远是S[i]的前缀。然后我们打表看看对于最小的斐波那契数列(a1 = 1, a2 = 1)有S[88] > 1e18,所以我们最多要考虑S的前88项就可。考虑到这个性质我们就可以考虑递归求解了。设f(n, now, c)是对于S[n],前now个字符里字符c的数量,则有递归式: 其中,f(n − 1, lenn − 1)这一项我们可以通过预处理获得。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=10005;
string a,b;
char c;
int q,l,r,lim;
int len[maxn],sum1[maxn][30],sum2[maxn][30],qzh[maxn][30];
int count(int n,int now)
{
if(now==0) return 0;
if(n==1) { return sum1[now][c-'a']; }
if(n==2) { return sum2[now][c-'a']; }
if(now<=len[n-1]) return count(n-1,now);
else return qzh[n-1][c-'a']+count(n-2,now-len[n-1]);
}
signed main()
{
cin>>a; cin>>b;
len[1]=a.size(); len[2]=b.size();
for(int i=3;i<maxn;i++)
{
if((len[i-1]+len[i-2])<1e18) len[i]=len[i-1]+len[i-2];
else { len[i]=len[i-1]+len[i-2]; lim=i; break; }
}
for(int i=0;i<=25;i++)
{
int len=a.size()-1;
for(int j=0;j<=len;j++)
{
if((j-1)>=0) sum1[j+1][i]=sum1[j][i];
if(i==(a[j]-'a')) sum1[j+1][i]++;
}
}
for(int i=0;i<=25;i++)
{
int len=b.size()-1;
for(int j=0;j<=len;j++)
{
if((j-1)>=0) sum2[j+1][i]=sum2[j][i];
if(i==(b[j]-'a')) sum2[j+1][i]++;
}
}
for(int i=0;i<=25;i++)
{
qzh[1][i]=sum1[len[1]][i];
qzh[2][i]=sum2[len[2]][i];

}
for(int i=3;i<=lim;i++)
{
for(int j=0;j<=25;j++)
{
qzh[i][j]=qzh[i-1][j]+qzh[i-2][j];
}
}
cin>>q;
while(q--)
{
cin>>l>>r>>c;
cout<<count(lim,r)-count(lim,l-1)<<endl;
}
return 0;
}

F:Strongly Connected 2

待补题。目前显然的想法是:由于有一条从N1的链,其实就是问对于M条边,有几种选边方案,使得1到任何点都联通。且观察到题目保证了所有有向边都有u < v,所以我们应该给他转化为一个线段覆盖之类的问题,然后用dp解决。