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;
}

posted @ 2021-08-22 19:08  随处可见的阿宅  阅读(47)  评论(0编辑  收藏  举报