AtCoder Beginner Contest 407(ABCDEF)

A - Approximation

翻译:

        给你一个正整数 A 和一个正奇数 B。
        请输出与实数  \frac{A}{B} 的差最小的整数。
        可以证明,在约束条件下,这样的整数是唯一的。

思路:

        令c=\lfloor \frac{A}{B}\rfloor。比较c+1-\frac{1.0*A}{B},\frac{1.0*A}{B}-1来判断答案。

实现:

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

void solve(){
    int a,b;
    cin>>a>>b;
    int c = a/b;
    if (1.0*a/b-c<(c+1)-1.0*a/b){
        cout<<c<<endl;
    }else{
        cout<<c+1<<endl;
    }
}

int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
    // cout<<fixed;
    // 四舍五入中间填保留几位小数,不填默认
    // cout.precision();
    solve();
    return 0;
}



B - P(X or Y)

翻译:

        掷两颗骰子,每颗骰子都有六个面 1、2、3、4、5、6。求以下两个条件中至少有一个成立的概率:

  • 两个结果之和至少为 X。
  • 两个结果的绝对差至少为 Y。

        每个骰子的每个面的可能性相同,且两个骰子是独立的。

思路:

        遍历所有情况并判断条件是否成立。

实现:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
int x,y;
bool check(int a,int b){
    return (a+b>=x || abs(a-b)>=y);
}
void solve(){
    cin>>x>>y;
    int cnt = 0;
    for (int i=1;i<=6;i++){
        for (int j=1;j<=6;j++){
            cnt+=check(i,j);
        }
    }
    cout<<1.0*cnt/36<<endl;
}

int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
     cout<<fixed;
    // 四舍五入中间填保留几位小数,不填默认
     cout.precision(9);
    solve();
    return 0;
}



C - Security 2

翻译:

        在 AtCoder 公司的入口处,有一个特殊的密码输入装置。该设备由一个显示一个字符串的屏幕和两个按钮组成。

        让 t 是屏幕上显示的字符串。最初 t 是空字符串。按下按钮后,t 会发生如下变化:

  • 按 A 按钮会在 t 的末尾添加 0。
  • 按 B 按钮将 t 中的每个数字替换为下一个数字。t 中的每一位数字替换为下一位数字。1;9 之后的下一位数为 0。

        例如 t 为 1984,按下 A 按钮、 t 就变成了 19840;如果按下 B 按钮,t 就变成了 20951、 t 就会变成 20951。

        给您一个字符串 S. 从空字符串开始,按下 0 次或更多次按钮,直到 t 与 S. 求最少需要按多少次按钮。

思路:

        s从后往前判断,当前数位为 i 时,说明到最终答案的状态要在加0后按i次,而之前的值都要也按 i 次。再下一个数位以此类推。(模拟)

实现:

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

void solve(){
    string s;
    cin>>s;
    int ans = s.size(),cnt = 0;
    for (int i=s.size()-1;i>=0;i--){
        int now = s[i]-'0';
        int need = (10+(now-cnt)%10)%10;
        ans+=need;
        cnt+=need;
    }
    cout<<ans<<endl;
}

int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
     cout<<fixed;
    // 四舍五入中间填保留几位小数,不填默认
     cout.precision(9);
    solve();
    return 0;
}

D - Domino Covering XOR

翻译:

        有一个 H 行 W 列的网格。让 (i,j) 表示位于 从上往下数第 i 行的单元格(1≤i≤H)和从左往下数第 j 列的单元格(1≤j≤W)。

        单元格 (i,j) (1≤i≤H,1≤j≤W) 上写有一个非负整数 A i,j。

        让我们在网格上放置零块或多块多米诺骨牌。一块多米诺骨牌覆盖两个相邻的单元格,即以下两对中的一对:

  • 单元格 (i,j) 和 (i,j+1) 为 1≤i≤H,1≤j<W;
  • 单元格 (i,j) 和 (i+1,j) 为 1≤i<H,1≤j≤W。

        任何单元格都不能被一块以上的骨牌覆盖。

        对于多米诺骨牌的摆放,其得分定义为写在未被任何多米诺骨牌覆盖的单元格中的所有整数的比特 XOR。

        求最大可能得分。

思路:

        数据量足够小,直接遍历所有情况(几块多米诺骨牌,每块多米诺骨牌的摆放方式)比较答案大小。(dfs)

实现:

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

void solve(){
    ll h,w;
    cin>>h>>w;
    vector<vector<ll>> maze(h,vector<ll>(w));
    ll now = 0,ans = 0;
    for (ll i=0;i<h;i++){
        for (ll j=0;j<w;j++){
            cin>>maze[i][j];
            now ^= maze[i][j];
        }
    }
    vector<vector<ll>> vis(h,vector<ll>(w,0));
    auto dfs = [&](auto&& dfs,ll cnt,ll x,ll y,ll now){
        if (cnt==0){
            ans = max(ans,now);
            return;
        }
        if (x==h-1 && y==w-1) return;
        // 不拿
        dfs(dfs,cnt,x+(y==w-1),(y+1)%w,now);
        // 拿
        if (vis[x][y]==0){
            vis[x][y] = 1;
            // 拿下
            if (x!=h-1 && vis[x+1][y]==0){
                vis[x+1][y] = 1;
                dfs(dfs,cnt-1,x+(y==w-1),(y+1)%w,now^maze[x][y]^maze[x+1][y]);
                vis[x+1][y] = 0;
            }
            // 拿右
            if (y!=w-1 && vis[x][y+1]==0){
                vis[x][y+1] = 1;
                dfs(dfs,cnt-1,x+(y==w-1),(y+1)%w,now^maze[x][y]^maze[x][y+1]);
                vis[x][y+1] = 0;
            }
            vis[x][y] = 0;
        }
    };
    for (int i=0;2*i<=h*w;i++){
        dfs(dfs,i,0,0,now);
    }
    cout<<ans<<endl;
}

int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
//     cout<<fixed;
    // 四舍五入中间填保留几位小数,不填默认
//     cout.precision(9);
    solve();
    return 0;
}

E - Most Valuable Parentheses

翻译:

        给你一个长度为 2N 的非负整数序列 A=(A 1 ,...,A 2N )。

        长度为 2N 的括号序列 s 的得分定义如下:

  • 对于 s 的第 i 个字符为 ) 的每个位置 i,设 A i  为 为 0,然后求 A 的所有元素之和。

        求长度为 2N 的正确括号序列的最大可能得分。

        给你 T 个测试用例,请逐个求解。

思路:

        序列A的两端是可以确定状态的,之后自前向后同时取两个放入大根堆,并从中取出最大的值,作为符号(。此过程保证了左括号始终大于等于右括号。(堆,贪心)

实现:

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

void solve(){
    ll n;cin>>n;
    vector<ll> a(2*n);
    for (ll &i:a) cin>>i;
    ll ans = a[0];
    priority_queue<ll> pq;
    for (ll i=1;i<n;i++){
        pq.push(a[2*i-1]);
        pq.push(a[2*i]);
        ans+=pq.top();
        pq.pop();
    }
    cout<<ans<<endl;
}

int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
//     cout<<fixed;
    // 四舍五入中间填保留几位小数,不填默认
//     cout.precision(9);
    ll t;cin>>t;
    while (t--) solve();
    return 0;
}

F - Sums of Sliding Window Maximum

翻译:

        给你一串长度为 N 的非负整数 A=(A 1 ,...,A N )。

        对于每个 k=1,...,N,求解以下问题:

  • A 有 N-k+1 个长度为 k 的(连续)子数组,求每个子数组的最大值,并输出这些最大值之和。

思路:

        以贡献法的思路实现。计算每个值作为最大值区间,如 0 2 4 3 1 0,值为4的点区间为【0,7】,那么在k = 1,2,3,4,5,6时,被用了 1,2,3,3,2,1次。即被用的次数为 1,2,3。。。x 。。。x,x-1,x-2。。。1。计算每个值区间可用单调栈,计算答案可使用二阶差分快速求。(单调栈,差分)

实现:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MX = 2e5+10;
struct Poll{
    ll val,l,r;
};
void solve(){
    ll n;cin>>n;
    vector<Poll> a(n+1);
    for (ll i=1;i<=n;i++) cin>>a[i].val;
    stack<ll> st;
    // 求出左端点,左边相同的点默认比较小
    for (ll i=1;i<=n;i++){
        while (!st.empty() && a[st.top()].val<=a[i].val) st.pop();
        if (!st.empty()) a[i].l = st.top();
        else a[i].l = 0;
        st.push(i);
    }
    while (!st.empty()) st.pop();
    // 求出右端点,右边相同的点默认比较大
    for (ll i=n;i>=1;i--){
        while (!st.empty() && a[st.top()].val<a[i].val) st.pop();
        if (!st.empty()) a[i].r = st.top();
        else a[i].r = n+1;
        st.push(i);
    }

    vector<ll> ans(n+3,0),ans1(n+3,0),ans2(n+3,0);
    // 二阶差分计算贡献
    for (ll i=1;i<=n;i++){
        ll l = i-a[i].l,r = a[i].r-i;
        if (l>r) swap(l,r);
        ans2[1] += a[i].val;
        ans2[l+1] -= a[i].val;
        ans2[r+1] -= a[i].val;
        ans2[1+l+r] += a[i].val;
    }
    for (ll i=1;i<=n;i++){
        ans1[i] = ans1[i-1]+ans2[i];
        ans[i] = ans[i-1]+ans1[i];
    }
    for (ll i=1;i<=n;i++) cout<<ans[i]<<"\n";
}

int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
//     cout<<fixed;
    // 四舍五入中间填保留几位小数,不填默认
//     cout.precision(9);
    solve();
    return 0;
}

之后补题会在此增加题解。    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cando-01

随心而动,随性而为。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值