AtCoder Beginner Contest 336

ABC336 总结

AtCoder Beginner Contest 336

A - Long Loong

翻译

给定一个数 \(n\),请输出一个由一个 L\(n\)o 、一个 n 和一个 g 组成的字符串(区分大小写)。

分析

按题意模拟即可。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;

int n;

int main ()
{
    cin>>n;
    cout<<"L";
    for(int i=1;i<=n;i++) cout<<"o";
    cout<<"ng"<<"\n";
    return 0;
}

B - CTZ

翻译

求一个正整数 \(N\) 二进制下末尾 \(0\) 的个数,\(1\le N\le 10^9\)

分析

直接 lowbit 操作,然后取 \(2\) 的对数。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n,m;

int main ()
{
    cin>>n;
    m=n&(-n);
    cout<<log2(m)<<"\n";
    return 0;
}

C - Even Digits

翻译

定义满足没有前导零,且十进制下每个数位都为偶数的非负整数为好数。

求第 \(N\) 小的好数。\(1\le N\le 10^{12}\)

分析

每个数位都是偶数,则每个数位都有五种情况,相当于把 \(n\) 转化为 \(5\) 进制数,再按照十进制来乘 \(2\)

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;

ll n,m,t,a;

int main ()
{
    cin>>n;
    n--;
    while(n)
    {
        m=n%5;
        n/=5;
        a+=m*t;
        t*=10;
    }
    cout<<a*2<<"\n";
    return 0;
}

D - Pyramid

翻译

对于正整数 \(k\),一个大小为 \(k\) 的“金字塔数列”为一个长度为 \(2k-1\) 的数列,里面的数字依次为 \(1,2,3,\dots k-1,k,k-1,\dots 3,2,1\)
现在给一个长度为 \(n\) 的数列 \(S\),你可以进行以下操作任意次,使得数列最后变为一个“金字塔数列”:

  • 选择一个数 \(i(1 \le i \le n)\),把 \(S_i\) 减少 \(1\)
  • 删除整个数列的第一个或最后一个数字。

问最后生成的“金字塔数列”的最大的 \(k\) 是多少。

分析

\(k\) 大小的“金字塔数列”,前 \(k\) 项单调递增,后 \(k\) 项单调递减,可以分开考虑,用线性 \(dp\)\(dp[i][0]\) 表示以 \(a_i\) 为末尾的,经过多次操作可以成为金字塔数列前 \(k\) 项的序列的最大长度,\(dp[i][1]\) 表示以 \(a_i\)为首的,经过多次操作可以成为金字塔数列后 \(k\) 项的最大长度,最终合并计算答案即可。

\[dp[i][0]=min(dp[i-1][0]+1,a[i]) \]

\[dp[i][1]=min(dp[i+1][1]+1,a[i]) \]

\[ans=max(ans,min(dp[i][0],dp[i][1])) \]

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;

int n,m,t,a[N],dp[N][3],ans;
int main ()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) dp[i][0]=min(dp[i-1][0]+1,a[i]);
    for(int i=n;i>=1;i--) dp[i][1]=min(dp[i+1][1]+1,a[i]);
    for(int i=1;i<=n;i++) ans=max(ans,min(dp[i][0],dp[i][1]));
    cout<<ans<<"\n";
    return 0;
}

F - Rotation Puzzle

翻译

gsczl71 有一个 \(H\) 行,\(W\) 列的二维数组。

每一次选择一个 \(H-1\) 行,\(W-1\) 列的连续矩阵,将其旋转 \(180\) 度。

目标:对于所有 \(1 \le i \le H,1 \le j \le W\),使得单元格 \((i,j)\) 中包含整数 \(\left(\left(i-1\right) \times W+j\right)\)

你有最多 \(20\) 次操作机会,问你最少操作多少次?

若不可以达到要求,输出 -1

分析

翻转只有四种情况,最大操作次数为 \(20\),直接搜索状态数可达 \(4^{20}=1099511627776\),直接爆掉,但如果用双向搜索(meet in the middle),每个方向最大深度为 \(10\),这样状态数则为 \(2 \times 4^{10}=2097152\),轻松通过。

初状态与末状态等价,两者相遇可用特殊的值来判断,比如初状态为 \(1\),末状态为 \(2\),那么判断相遇就是值为 \(3\) 的时候。初末状态等价,可以只用一个队列,翻转操作需要略加思考,容易出错。可以用 stringmap 实现 hash,将二维数组转化为字符串和字符串还原为数组与八数码相同。

注意:原数组出现相同的数则一定无法实现,输出 -1,初末状态相同就不需要操作,输出 0

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=10;

int m,n,a[N][N],b[N][N],tong[N*N],f[5][3]={{1,1},{0,1},{1,0},{0,0}},c[N][N];
string st,ed;
map<string,int> vis,d,v;
string reverse(int x,int y)
{
    string s;
    for(int i=1;i<n;i++)
        for(int j=1;j<m;j++)
                c[i+x][j+y]=b[n-i+x][m-j+y];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            s+=c[i][j]+'0';
    return s;    
}
void restore(string s)
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            c[i][j]=b[i][j]=s[(i-1)*m+j-1]-'0';
}
int bfs(string x,string y)
{
    queue<string> q;
    q.push(x);q.push(y);
    vis[x]=1;d[x]=0;
    vis[y]=2;d[y]=0;
    while(q.size())
    {
        string t=q.front();q.pop();
        for(int i=0;i<4;i++)
        {
            restore(t);
            int l=f[i][0],r=f[i][1];
            string s=reverse(l,r);
            if(vis[s]==vis[t]) continue;
            if(vis[s]+vis[t]==3) return d[s]+1+d[t];
            d[s]=d[t]+1;
            if(d[s]>10) return 21;
            vis[s]=vis[t];
            q.push(s);
        }
    }
    return 21;
}
int main ()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
            st+=a[i][j]+'0';
            tong[a[i][j]]++;
        }
    for(int i=1;i<=n*m;i++) 
    {
        if(tong[i]!=1) 
        {
            cout<<-1<<"\n";
            return 0;
        }
        ed+=i+'0';
    }
    if(ed==st)
    {
        cout<<0<<"\n";
        return 0;
    }
    int ans=bfs(st,ed);
    if(ans>20) cout<<-1<<"\n";
    else cout<<ans<<"\n";
    return 0;
}
posted @ 2024-02-01 21:12  zhouruoheng  阅读(48)  评论(2编辑  收藏  举报