Codeforces Round #829 (Div. 2) A-E

废话:本来前50分钟kill完了A B C1 D的时候是前300,看着C2过的人很少就想着摆了,结果刷了会儿视频一看我都排到700了,这才开始做C2,结果到最后C2卡线过的,E应该能过也没时间想了。直接排名干到700+了。

Codeforces Round #829 (Div. 2)

正题

A. Technical Support(思维)

题意:给定一个qa序列,要求每个q后面都必须有a可以和他对应

分析:全场唯一一发wa是A题。

q后面必须有足够的a要大于等于目前的q的数量就可以了,当:目前的q被a匹配光了之后,不能继续克扣q的数量。

#include <iostream>

using namespace std;
#define int long long
#define endl '\n'
#define first fi
#define second se
const int N = 2e6+100;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int lcm(int a, int b) {
    return a * b / gcd(a, b);
}
char s[N];
int a[N];
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        cin>>(s+1);
        int now=0;
        for(int i=1;i<=n;i++)
        {
            if(s[i]=='Q')
            {
                now++;
            }
            else if(now>0)
            {
                now--;
            }
        }
        if(now<=0)
        {
            cout<<"Yes"<<endl;
        }
        else
        {
            cout<<"No"<<endl;
        }

    }
    return 0;
}

B. Kevin and Permutation(数列,思维)

题意:要求输出一个长度为n个排列,使得其相邻两项差值的最小值最大。

分析:一眼分块输出,不是中间开始分,就是奇偶分,再不然就是根号分。随便试一下发现是中间开始的数列分块(此分块非彼分块)

#include <iostream>

using namespace std;
#define int long long
#define endl '\n'
#define first fi
#define second se
const int N = 2e6+100;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int lcm(int a, int b) {
    return a * b / gcd(a, b);
}
char s[N];
int a[N];
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        int l=n/2+n%2;
        int r=n;
        for(int i=1;i<=n;i++)
        {
            if(i&1)
            {
                cout<<l<<" ";
                l--;
            }
            else
            {
                cout<<r<<" ";
                r--;
            }
        }
        cout<<endl;
    }
    return 0;
}

C2. Make Nonzero Sum (hard version)(思维,数学)

题意:给定一个只包含 1 0 -1的数组,请你把这个数组划分为若干的连续区间(l,r)。有一个函数sum(l,r)=a[l]-a[l+1]+a[l+2]-a[l+3]…a[r]这样,要求你划分的若干个区间的sum函数之和为0

思路:给的所有数如果和他相邻的下一项组合的话,那么就可以在保证本身符号不变的情况下扭转下一项的符号,所以实际上就变成了这样的一个题:
1.绝对值为1的数有贡献
2.有贡献的数前面的符号分为正负两种
3.当一个数前面有其他数的时候,可以扭转这个数的正负号,但是之后这两个数都不能再被选中。
4.正负号数量相等

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
const int N = 2e6+100;
int n,a[N],vis[N];
void init()
{
    for(int i=1;i<=n;i++)
        vis[i]=0;
}
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
    {
        init();
        cin>>n;
        int cnt1=0,cnt2=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            if(a[i]==1)
            {
                cnt1++;
            }
            else if(a[i]==-1)
            {
                cnt2++;
            }
        }
        if(cnt1>cnt2)//情况1 1的数量多,需要扭转-1
        {
            for(int i=2;i<=n;i++)
            {
                if(a[i]==1)
                {
                    vis[i-1]=vis[i]=1;
                    cnt1--;
                    cnt2++;
                    i++;
                }
                if(cnt1==cnt2)//扭转足够
                {
                    break;
                }
            }
        }
        else if(cnt1<cnt2)//情况2 -1的数量多,扭转1的数量
        {
            for(int i=2;i<=n;i++)
            {
                if(a[i]==-1)
                {
                    vis[i-1]=vis[i]=1;
                    cnt1++;cnt2--;
                    i++;
                }
                if(cnt1==cnt2)//扭转足够
                {
                    break;
                }
            }
        }
        if(cnt1==cnt2)
        {
            vector<pair<int,int>>ans;
            for(int i=1;i<=n;i++)
            {
                if(vis[i])
                {
                    ans.push_back(make_pair(i,i+1));
                    i++;
                }
                else
                {
                     ans.push_back(make_pair(i,i));
                }
            }
            cout<<ans.size()<<endl;
            for(auto x:ans)
            {
                cout<<x.first<<" "<<x.second<<endl;
            }
        }
        else
        {
            cout<<-1<<endl;
        }
    }
    return 0;
}

D. Factorial Divisibility(数论,进位)

题意:给定一个数组a和一个数x,判定这个数组的所有元素的阶乘和能否被x的阶乘整除。

思路:暴力?就算是简单也不会给你暴力的。

我们想想,如果y想被x整除的话,那么是不是y必须是x的倍数。

那么y是x的倍数的话,y一定不能比x小对吧?

回到这个题上来,所有元素的阶乘的和视为y,那么想办法判断能成为x的倍数即可。
比如x是6
然后你得有六个 5才行,因为这样才能爬到对应位

这样层层进位像是:两个一进一位2,三个2进一位1,四个3进一位4。
只要出现了进位后有余数的情况那么就可以判断不能被x!整除了。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 2e6+100;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int lcm(int a, int b) {
    return a * b / gcd(a, b);
}
char s[N];
int a[N];
int sum[N];
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int n,m;
    int t=1;
    //cin>>t;
    while(t--){
    cin>>n>>m;
    map<int,int>mp;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        mp[a[i]]++;
    }
    bool falg=true;
    for(int i=1;i<=m-1;i++)
    {
        if(mp[i]%(i+1)==0)
        {
            mp[i+1]+=mp[i]/(i+1);
        }
        else
        {
            falg=false;
        }
    }
    if(falg)
        cout<<"Yes"<<endl;
    else
        cout<<"No"<<endl;
    }
    return 0;
}

E. Wish I Knew How to Sort(概率期望,概率论)

题意:给定一个01串,每次可以选择一对下标[i,j] (i!=j),然后交换这两个下标对应的数,问你将整个串交换为有序的期望是多少。

思路:

抽象模型
首先假设我们有x个0,那么题目期望达到的最终状态就是前x个位置都是0,也就是要把前x个位置里的前的所有1都交换出去。

1.概率论基础:若干事件的期望是每个事件期望的和。
应用到这个题上就是:每个1被交换出去的期望相加。

再来每个1被交换出去的期望,发现一共有n*(n-1)/2个下标对可以选择,其中满足能把1交换出去的是cntcnt(cnt是当前遍历到的前x个位置中1的个数)个。所以成功选择的概率就是cnt * cnt/(n(n-1)/2)

2.伯努利事件与几何分布。
请添加图片描述

请添加图片描述

在这里插入图片描述

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 2e6+100;
const int mod =998244353;
int fastpow(int n,int a)
{
    int res=1;
    a%=mod;
    while(n)
    {
        if(n&1)
        {
            res=res*a%mod;
        }
        a=a*a%mod;
        n>>=1;
    }
    return res%mod;
}
int a[N];
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;
    for(cin>>t;t;t--)
    {
        int n;
        cin>>n;
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            if(!a[i])
                cnt++;
        }
        int x=0;
        int tot=n*(n-1)/2;
        tot%=mod;
        int ans=0;
        for(int i=1;i<=cnt;i++)
        {
            if(a[i])
            {
                x++;
                ans=(ans%mod+tot*fastpow(mod-2,x*x)%mod+mod)%mod;
            }
        }
        cout<<ans<<'\n';
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值