Codeforces Round #450 (Div. 2)

本文提供了Codeforces Round #450 (Div.2)的五道题目的解题思路及代码实现,涵盖水题到较复杂的问题解决策略,通过巧妙的数据结构和算法优化提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Codeforces Round #450 (Div. 2)

A:水

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int a=0,b=0;
    int n;
    cin >> n;
    while(n--)
    {
        int x,y;
        cin >> x >> y;
        if(x<0) ++a;
        else ++b;
    }
    if(a<=1||b<=1) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}

B:

题意是求出 c a/b 小数部分中第一次出现的位置。
求小数部分可以用求长除法的过程,因为分母是 b ,所以余数最多有 b 种,所以循环节最多长 b1 。因此迭代 b1 次长除法过程即可。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int a,b,c,ans=0;
    cin >> a >> b >> c;
    int k=b;
    while(k--)
    {
        ++ans;
        a*=10;
        if(a/b==c)
        {
            printf("%d\n",ans);
            return 0;
        }
        a%=b;
    }
    puts("-1");
    return 0;
}

C:
题意是排列中满足 aj<ai 对于所有 j<i ai 是一个record,问删除哪一个数后使得数列的record数量最大。
可以用 set 维护 ai 之前的所有 aj ,扫一遍可以求出没删任何数时 ai 是否为record,用 b[i] 表示,那么 B=b[i] 就是所有没删之前record的数量。
一个数变为record的条件是它之前只有一个数比它大,且这个数被删除。那么同样可以用 set 维护,设删除一个数后有多少个在它后面的数从非record变为record,然后求 max(Bb[i]+c[i]) 就是答案。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
int a[N],p[N],c[N],b[N];
int main()
{
    int n;
    scanf("%d",&n);
    set<int> s;
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a[i]);
        p[a[i]]=i;
        s.insert(a[i]);
    }
    for(int i=n;i>=1;--i)
    {
        s.erase(a[i]);
        auto it = s.upper_bound(a[i]);
        if(it == s.end()) b[i]=1;
        else
        {
            ++it;
            if(it == s.end())
            {
                --it;
                c[p[*it]]++;
            }
        }
    }
    int ans = 1000000,cnt = 0,cc=0;
    for(int i=1;i<=n;++i) cc+=b[i];
     for(int i=1;i<=n;++i)
    {
        if(c[i]+cc-b[i]>cnt||(c[i]+cc-b[i]==cnt&&a[i]<ans))
        {
            ans=a[i];
            cnt=c[i]+cc-b[i];
        }
    }
    printf("%d\n",ans);
    return 0;
}

D:
题意可以转化为求有多少个数列满足gcd为1且和为 yx
f(t) 为有多少个数列满足gcd为1且和为 t
g(t) 为有多少个数列满足和为 t
可以得到下式:

g(t)=d|tf(td)

那么 f(t)=g(t)d|td1f(td)
又因为 g(t)=2t1 。且 t 的因数是开立方级别的。可以先预处理出 y/x 的所有因数,然后就变成了dp问题了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
ll ans;
ll powm(ll a, ll b)
{
    ll c = 1;
    while(b)
    {
        if(b&1) c=c*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return c;
}
int main()
{
    int x,y;
    scanf("%d %d",&x,&y);
    if(y%x)
    {
        puts("0");
        return 0;
    }
    y/=x;
    vector<int> a;
    for(int i=1;i*i<=y;++i)
    {
        if(y%i==0)
        {
            a.push_back(i);
            if(i*i!=y) a.push_back(y/i);
        }
    }
    vector<ll> dp(a.size());
    sort(a.begin(), a.end());
    int n = a.size();
    for(int i=0;i<n;++i)
        dp[i]=powm(2, a[i]-1);
    for(int i=0;i<n;++i)
        for(int j=i+1;j<n;++j)
            if(a[j]%a[i]==0) dp[j]=(dp[j]-dp[i]+mod)%mod;
    printf("%I64d\n",dp.back());
    return 0;
}

E:
可以求出连续的从 i 开始 abab... 数量 ai
求出问号前缀和 pre[i]
然后就变成dp了。

dp[i+1]=max(dp[i+1],dp[i])

dp[i+m]=max(dp[i+m],pair(dp[i]+1,dp[i]+pre[m]pre[i]))

答案就是 dp[n].second
max的定义是数量最大消耗问号最小。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
char s[N];
struct Node
{
    int c,w;
    Node():c(0),w(0){}
    Node(int c,int w):c(c),w(w){}
    bool operator < (const Node & r) const
    {
        return c<r.c||(c==r.c&&w>r.w);
    }
};
Node dp[N];
int a[N]; //consecutive 'aba...'
int b[N]; //consecutive 'bab...'
int p[N]; //prefix sum of count of '?'
int main()
{
    int n,m;
    scanf("%d",&n);
    scanf("%s",s+1);
    scanf("%d",&m);
    for(int i=n;i>=1;--i)
    {
        if(s[i]=='a')
        {
            a[i]=b[i+1]+1;
            b[i]=0;
        }
        else if(s[i]=='b')
        {
            b[i]=a[i+1]+1;
            a[i]=0;
        }
        else
        {
            a[i]=b[i+1]+1;
            b[i]=a[i+1]+1;
        }
    }
    for(int i=1;i<=n;++i)
        p[i]=p[i-1]+(s[i]=='?');
    for(int i=0;i<n;++i)
    {
        dp[i+1]=max(dp[i+1],dp[i]);
        if(a[i+1]>=m&&i+m<=n)
            dp[i+m]=max(dp[i+m],Node(dp[i].c+1,dp[i].w+p[i+m]-p[i]));
    }
    printf("%d\n",dp[n].w);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值