Codeforces Round #714 (Div. 2) A+B+C

A. Array and Peaks

题意:构造一个排列满足有k个peaks。
peaks: 对于a[i](1<i<n), 满足a[i]>a[i-1] && a[i]>a[i+1],则称i为一个peaks。

分析:可以看出,长度为n的排列最多只能有(n-1)/2个。说明6个和5个的效果是一样的,8个和7个的效果一样…
构造形如1 3 2 5 4…的排列

即:如果遇到偶数,直接加到后面,如果遇到奇数,加完后和前一位交换位置。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 1e5+10;
const int mx = 40;
const int mod = 1e9+5;
const ll inf = 34359738370;
const int INF = 1e9+7;
//构造排列满足有k个peaks  a[i]>a[i-1] a[i]>a[i+1] 1<i<n
int n,k;
int main()
{ 
    int t;cin>>t;
    while(t--)
    {
        int ans[105]={0};
        scanf("%d %d",&n,&k);
        if((n-1)/2 < k) 
        {
            puts("-1");
            continue;
        }
        if(!k)
        {
            for(int i=1;i<=n;i++) cout<<i<<' ';
            cout<<'\n';
            continue;
        }
        ans[1]=1;
        ans[2]=3;
        ans[3]=2;
        int cnt=1,i=4;
        for(;cnt<k && i<=n;i++)
        {
            if(i&1) 
            {
                ans[i]=i;
                swap(ans[i],ans[i-1]);
                cnt++;
            }
            else ans[i]=i;
        }
        for(;i<=n;i++) ans[i]=i;
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);
        cout<<'\n';
    }
    return 0;
}

B. AND Sequences

题意:给定一堆数, 问有多少种排列方式满足好数列的定义
:对于[1,n-1]中的每个i,有 a[1]&a[2]…&a[i]=a[i+1]&a[i+2]…&a[n]。

  • 分析式子:

  • a[1]=a[2]&a[3]&…a[n] <=> a[1]=a[1]&a[2]…&a[n]

  • a[1]&a[2]=a[3]…&a[n] <=>a[1]&a[2]=x (这个式子恒成立当且仅当a[1]==x)

  • 所以当a[1]==a[n]==a[1]&a[2]&a[3]…&a[n] 的时候, 上述式子一定成立

      故而只要找出两个值为a[1]&a[2]...&a[n]的元素,放在开始和结尾,其余位置任意就行.
    
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 2e5+10;
const int mx = 40;
const int mod = 1e9+7;
const ll inf = 34359738370;
const int INF = 2e9+7;
//给定一堆数 问有多少种排列方式满足好数列的定义:
//对于[1,n-1]中的每个i,有 a[1]&a[2]..&a[i]=a[i+1]&a[i+2]...&a[n]

ll A[maxn];//阶层
int n,a[maxn];
int x;
int main()
{ 
    A[0]=1;
    A[1]=1;
    for(int i=2;i<=maxn;i++)
    {
        A[i]=(i*A[i-1])%mod;
    }
    int t;cin>>t;
    while(t--)
    {
        int num=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",a+i);
            if(i==1) x=a[1];
            else x&=a[i];
        }
        for(int i=1;i<=n;i++) 
        {
            if(x==a[i]) num++;
        }
        if(num>=2) 
        {
            printf("%I64d\n",1ll*num*(num-1)%mod*(A[n-2])%mod);
        }
        else puts("0");
    }
    return 0;
}

C. Add One

题意:给定整数n,m。 表示有m次操作,每次把n的每一位都加1,每一位独立地按十进制进位。 29->310
问m次操作之后,n的长度。

分析:很显然每一位都是独立的,我们把每一位的答案加起来就可以得到这题的答案。
我们打个表,
在这里插入图片描述
然后把数据用OEIS分析一下可以得出规律,:

dp[i]=dp[i-9]+dp[i-10] 
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 2e5+12;
const int mx = 40;
const int mod = 1e9+7;
const ll inf = 34359738370;
const int INF = 1e9+7;
ll dp[maxn];
char s[maxn];
int m;
int main()
{ 
    //dp[i]表示 对于1而言,操作i次后的位数 
    for(int i=0;i<=8;i++) dp[i]=1;
    dp[9]=2,dp[10]=2;
    for(int i=11;i<=maxn;i++)
    {
        dp[i]=(dp[i-9]+dp[i-10])%mod;
    }
    int t;cin>>t;
    while(t--)
    {
        ll ans=0;
        scanf("%s %d",s+1,&m);
        int len=strlen(s+1);
        for(int i=1;i<=len;i++)
        {
            //s[i]-'1'是和1相比 多操作的次数
            ans=(ans+dp[m+s[i]-'1'])%mod;
        }
        cout<<ans<<'\n';
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值