Codeforces Round 930 (Div. 2) (A、B)

原题链接
我太菜了只会两道T_T

A. Shuffle Party

题目大意:给一个从 1 到 n 的排列 1 , 2 , 3 , . . . , n 1,2,3,...,n 1,2,3,...,n 要求从 2 开始对每个数 k 找出其最大因数 x,并交换 a x a_x ax a k a_k ak ,当结束操作后 1 所在的位置。
列出前几个,找规律:
1 2
2 1 3 2-2
3 1 2 4 3-2
3 4 2 1 5 4-4
5 4 2 1 3 6 5-4
5 4 6 1 3 2 7 6-4
7 4 6 1 3 2 5 8 7-4
7 4 6 8 3 2 5 1 9 8-8
不难发现 n 次操作后 1 一定在小于等于 n 的最大的 2 y 2^y 2y 的位置上

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int t;
    cin>>t;
    while(t--) {
        ll n,ans=1;
        cin>>n;
        while(1<<ans<=n) ans++;
        ans--;
        cout<<(1<<ans)<<'\n';
    }
    return 0;
}

B. Binary Path

题目大意:给定一个 2 行 n 列的矩阵,其中只包含 0 或 1,找出从左上角到右下角路径字符串字典序最小的路线,并指出这样的路线有几条。
由于题目要求路径字符串的字典序最小,那么当前不断选择 0 (如果能的话)一定是最优解,当我们已经走到第二行时,唯一的选择是不断向右走;当处于第一行时,假如当前位置的右边和下面都为 0 ,那么选择向右走一定比向下走更优,因为向下走之后就只有一种选择(向右走),而向右走仍然保持着两种选择(向右与向下)。
在得到答案路径的字符串 str 后,我们便可以根据这个字符串来维护到每个点(i、j)的路径数 dp[i][j]

  • 首先计算第一行的 dp 的值,初始化起点的路径数 dp[0][0] = 1 从起点后面一个点开始向后遍历,如果第 j 列的字符等于 str 中对应位置时,dp[0][j] = 1 否则跳出循环
  • 计算第二行,由于第二行可以从第一行下来,所以对于每列 j 如果与str中对应位置字符相等,那么 dp[1][j] = (dp[0][j] + dp[1][j - 1])
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[2][200010];
void solve()
{
    int n;
    cin>>n;
    string mp[2];
    cin>>mp[0]>>mp[1];
    string ans="";
    ans+=mp[0][0];
    int x=0,y=0;
    while(x!=1||y!=n-1) {
        if(y==n-1) {
            x++,ans+=mp[x][y];
            continue;
        }
        if(x==0) {
            if(mp[0][y+1]=='0') {
                y++;
                ans+='0';
            } else if(mp[1][y]=='0') {
                x++;
                ans+='0';
            } else {
                y++;
                ans+='1';
            }
        } else {
            ans+=mp[x][++y];
        }
    }
    cout<<ans<<'\n';
    vector<vector<int>> dp(2,vector<int> (n));
    dp[0][0]=1;
    for(int i=1;i<n;i++) {
        if(mp[0][i]==ans[i])
            dp[0][i]=1;
        else break;
    }
    for(int i=0;i<n;i++) {
        if(mp[1][i]==ans[i+1]) {
            dp[1][i]+=dp[0][i];
            if(i-1>=0) dp[1][i]+=dp[1][i-1];
        }
    }
    cout<<dp[1][n-1]<<'\n';
}
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int t;
    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}
  • 41
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值