AtCoder Beginner Contest 215 A~F 题解
本场链接:AtCoder Beginner Contest 215
闲话
感觉有些不在状态,傻逼题都做不出来,脑子想不进去.GH不知道能不能做,能做再说.
A - Your First Judge
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
int main()
{
string s;cin >> s;
if(s == "Hello,World!") cout << "AC\n";
else cout << "WA\n";
return 0;
}
B - log2(N)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
int main()
{
ll n;cin >> n;
int res = 0;
forn(k,0,62) if((1ll << k) <= n) res = k;
printf("%d\n",res);
return 0;
}
C - One More aab aba baa
注意去重.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
const int N = 100;
char s[N];
int d[N];
int main()
{
int k;scanf("%s%d",s + 1,&k);int n = strlen(s + 1);
forn(i,1,n) d[i] = i;
vector<string> all;
do
{
string cur;
forn(i,1,n) cur += s[d[i]];
all.push_back(cur);
} while (next_permutation(d + 1,d + n + 1));
sort(all.begin(),all.end());all.erase(unique(all.begin(),all.end()),all.end());
cout << all[k - 1] << endl;
return 0;
}
D - Coprime 2
正难则反:考虑所有会有\(gcd(a_i,k) = d\)且\(d \neq 1\)的\(k\).显然这样的\(k\)是\(a_i\)的一个约数\(d\)的若干倍.那么枚举出所有\(a_i\)的约数,并且把这些约数自己和所有约数的倍数全部打上标记,被标记的点就是存在\(gcd(a_i,k) = d\)且\(d \neq 1\)的\(k\).如此,统计最后没有被标记的数即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
const int N = 1e5+7;
bool st[N];
int main()
{
int n,m;scanf("%d%d",&n,&m);
forn(i,1,n)
{
int a;scanf("%d",&a);
for(int d = 1;1ll * d * d <= a;++d)
{
if(a % d != 0) continue;
st[d] = 1;
st[a / d] = 1;
}
}
st[1] = 0;
forn(i,2,N - 1)
{
if(!st[i]) continue;
for(int j = i;j <= N - 1;j += i) st[j] = 1;
}
vector<int> res;
forn(i,1,m) if(!st[i]) res.push_back(i);
printf("%d\n",(int)res.size());
for(auto& _ : res) printf("%d\n",_);
return 0;
}
E - Chain Contestant
因为$ |\sum| = 10$考虑状压:
- \(f[i][j][k]\)表示做完第\(i\)个位置,当前已经选出的元素集合是\(j\)且末尾元素是\(k\)的方案数.
- 入口:\(f[i][(1 << s_i)][s_i] = 1\).
- 转移:若不放入 \(s_i\) 显然 $ += f[i - 1][j][k]$ ;若放入 \(s_i\),可能会有两种情况:要么\(s_i\)是第一次出现在序列里,作为起点;要么\(s_i\)是接到当前已经有的屁股后面,显然这个已经有的必须是当前的末尾.如果是接到后面,让\(f[i][j][k] += f[i - 1][j][k]\),此时需要满足\(k == j\).反过来如果\(k\)不属于\(j\)集合,那么此时放入\(s_i\)就是作为一个新的起点:\(f[i][j | (1 << s_i)][k] += \sum_{z \neq k} f[i - 1][j][z]\).(在具体实现的时候,如果转移方程是正确的,那么\(z == k\)的时候也不会有问题,因为\(j\)里面不包含\(k\)的情况下方案数是\(0\))
- 出口:\(res = \sum_{j,k} f[n][j][k]\).
入口可以不直接写出,在转移时给加一即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
const int N = 10,M = (1 << 10),C = 1020,MOD = 998244353;
int f[C][M][N];
char s[C];
int main()
{
int n;scanf("%d",&n);
scanf("%s",s);
forn(i,1,n)
{
int x = s[i - 1] - 'A';
forn(j,0,(1 << 10) - 1) forn(k,0,9)
{
f[i][j][k] = f[i - 1][j][k];
if(k == x) f[i][j][k] = (1ll * f[i][j][k] + f[i - 1][j][k]) % MOD;
}
forn(j,0,(1 << 10) - 1)
{
if(j >> x & 1) continue;
forn(k,0,9) f[i][j | (1 << x)][x] = (1ll * f[i][j | (1 << x)][x] + f[i - 1][j][k]) % MOD;
}
f[i][1 << x][x] = (f[i][1 << x][x] + 1) % MOD;
}
int res = 0;
forn(j,0,(1 << 10) - 1) forn(k,0,9) res = (res + f[n][j][k]) % MOD;
printf("%d\n",res);
return 0;
}
F - Dist Max 2
使最小值最大,考虑二分答案:二分最终答案\(ans \geq L\)?
\(ans \geq L\) 等价于 \(\min(|x_i - x_j|,|y_i - y_j|) \geq L\),即 \(|x_i - x_j| \geq L,|y_i - y_j| \geq L\) 同时满足.
如此,check
函数等价于求解:对于每个位置 \(i \in [1,n - 1]\),是否存在一个 \(j \in [i + 1,n]\) 同时满足如上两个条件.如果把绝对值拆掉,可以得到四个不等式,满足其中一个不等式即可.由于\((i,j)\)的相对次序可以忽略,可以将所有点按照 \(x\) 坐标上升排序,这样可以删掉其中两个,最后剩下: \(x_j - x_i \geq L \&\& y_i - y_j \geq L\) 或 \(x_j - x_i \geq L \&\& y_j - y_i \geq L\) 满足其一即可.
排序之后保证了一维偏序关系,剩下的一维偏序关系可以发现只需要找到:在某个后缀中\(y\)的最大值或最小值,因为要看是否存在一个 \(j \in [i + 1,n]\) 满足 \(y_j - y_i \geq L\) 那肯定取 \(y_j\) 的最大值.分别记作 \(Rmin/Rmax\).即可将 check
的复杂度做到 \(O(nlogn)\).
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
#define x first
#define y second
const int N = 2e5+7;
pii p[N];
int Rmin[N],Rmax[N];
int n;
bool check(int L)
{
forn(i,1,n - 1)
{
int pos = lower_bound(p + i + 2,p + n + 1,pii{p[i].x + L,0}) - p;
if(pos == n + 1) continue;
if(Rmax[pos] >= L + p[i].y || Rmin[pos] <= p[i].y - L) return 1;
}
return 0;
}
int main()
{
scanf("%d",&n);
forn(i,1,n) scanf("%d%d",&p[i].x,&p[i].y);
sort(p + 1,p + n + 1);
Rmin[n] = p[n].y;Rmax[n] = p[n].y;
forr(i,1,n - 1) Rmin[i] = min(Rmin[i + 1],p[i].y),Rmax[i] = max(Rmax[i + 1],p[i].y);
int l = 0,r = 2e9,idx = 0;
while(l < r)
{
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n",l);
return 0;
}