CF#587Div3

#587Div3

A

题意

  • 给定一个字符串只含 \(a,b\)
  • 使得每个前缀的 \(a\)\(b\) 的个数相同(当然是偶数位上的

解法

  • 一路改,哪个多就变成另一种

100分代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
char x,good[200005];
int n,one,two,ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        cin>>x;
        if(x=='a') one++;
        else two++;
        if(i%2) {
            good[i]=x;
            continue;
        }
        if(one==two){
            good[i]=x;
            continue;
        }
        ans++;
        if(one>two) good[i]='b',two++,one--;
        else good[i]='a',one++,two--;
    }
    printf("%d\n",ans);
//  cout<<c<<endl;
    for(int i=1;i<=n;i++) cout<<good[i];
    return 0; 
}

B

题意

  • 排序

解法

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int n,ans;
struct node{
    int id,x;
}d[1005];
bool cmp(node a,node b){
    return a.x >b.x ;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&d[i].x),d[i].id =i;
    sort(d+1,d+n+1,cmp);
    for(int i=1;i<=n;i++)
        ans+=d[i].x*(i-1)+1;
    printf("%d\n",ans);
    for(int i=1;i<=n;i++) printf("%d ",d[i].id );
    return 0;
}

D

题意

  • \(n\) 个数,有 \(y\) 个数是被减掉了若干个\(z\)后的,最初都是 \(x\)
  • 求最小的 \(y\)\(z\)

    解法

  • 从小到大排序,我们按照最大数当 \(x\) ,求出其他数和最大值的差,求这些差值的最大公约数。就是最少的人数。差值的和是剪掉多少个 \(z\)

    代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#define ll long long 
using namespace std;
int n;
ll ans,gd;
ll a[200005];
ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<n;i++){
        a[i]=a[n]-a[i];
        ans+=a[i];
        gd=gcd(gd,a[i]);
    }
    printf("%lld %lld",ans/gd,gd);
    return 0;
}

E1

题意

类似这样的数列 1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6......
求第 \(n\)
\(n<10^9\)

解法

按个数分组,第一组是1 第二组是 1 2 第三组是 1 2 3 第n组是 1 2 3 4 5 ...n
暴力找到在哪个组
再预处理出1-n个数的第几项是0-9中的哪个数
暴力在这个组内,找到答案

100分代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath> 
using namespace std;
int Q,res,cnt,maxx;
int num[500005],p[500005],now[500005];
struct node{
    int id,k,ans;
}q[505];
bool cmp(node a,node b){
    return a.k <b.k ;
}
bool cmp2(node a,node b){
    return a.id <b.id ;
}
int main()
{
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++){
        scanf("%d",&q[i].k);
        q[i].id =i;
        maxx=max(maxx,q[i].k);
    }
    sort(q+1,q+Q+1,cmp);
    maxx=sqrt(2*maxx)+1;
    for(int i=1;i<=maxx;i++){
        int x=i,cnt=0;
        while(x){
            now[++cnt]=x%10;
            x/=10;
        }
        num[i]=num[i-1]+cnt;
        while(cnt){
            ++res;
            p[res]=now[cnt];
            --cnt;
        }
    }
    int from=1,last=0;
    for(int i=1;i<=Q;i++){
        while(from<=maxx){
            if(num[from]+last<q[i].k){
                last+=num[from++];
                continue;
            }
            
            q[i].k -=last;
            q[i].ans =p[q[i].k];
            break;
        }
    }
    sort(q+1,q+Q+1,cmp2);
    for(int i=1;i<=Q;i++) printf("%d ",q[i].ans );
    return 0;
}

E2

n<10^18

  • 首先二分在哪个组,然后二分在这个组的哪个位置
  • 考虑
  • 1
  • 1 2
  • 1 2 3
  • 1 2 3 4
  • 1 2 3 4 5
  • 1 2 3 4 5 ....9
  • 1 2 3 4 5 6 ... 10
  • 设位数是 \(n\)
  • 上面这个三角形前x行的位数和,可以通过把位数分类,位数相同的在一类。
  • 这样就可以如下图一样求
  • enter image description here

enter image description here

每一个三角形的数位和是 \(j*(9*i)*(9*i+1)/2\) ,每个三角形下的矩形面积是 \(j*9*i*(x-10*i+1)\)
\(j\) 是指这一类数的位数, \(i=10^{j-1}\)
三角形算和相当于是一个等差数列求和

  • 注意边界,因为10是算在第二组的

  • 然后二分出组后,再二分在组中的位置
  • 看下面找规律

1 2 3 4 5 6 7 8 9
\(1*9*10^0=1*(9-1+1)\)

10 11 12 13 14 15 16 .... 99
\(2*9*10^1=2*(99-10+1)\)

100 101 102 103 104 105 106 107 .....999
\(3*9*10^3=3*(999-100+1)\)

\(10^x\) \(10^x+1\) \(10^x+2\) \(10^x+3\) \(...10^{x+1}-1\)
\((x+1)*9*10^{x+1}=(x+1)*(10^{x+1}-1-10^x+1)\)

  • \(i=10^{x},j=x+1\)
  • 每种数位相同的数有 \(9*i*10*j\) 个,遇到不是10的整数倍的,就 \((n-i+1)*j\)

100分代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long 
using namespace std;
ll n,x;
int T;
ll check1(ll x){
    ll now=0;
    for(ll i=1,j=1;i<=x;i*=10,j++){
        if(10*i<=x) now+=(9*i*(x-i*10+1)*j)+j*(9*i*(1+9*i))/2;
        else now+=j*(x-i+1)*(x-i+2)/2;
        if(now>1e18) return 1e18;
    }
    return now;
}
ll check2(ll x){
    ll now=0;
    for(ll i=1,j=1;i<=x;i*=10,j++){
        if(i*10<=x) now+=9*i*j;
        else now+=(x-i+1)*j;
        if(now>1e18) return 1e18;
    }
    return now;
}
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%lld",&x);
        ll l=0,r=1e9,mid;
        while(l<=r){//二分组数 
            mid=(l+r)>>1;
            if(check1(mid)<x) l=mid+1;
            else r=mid-1;
        }
        x-=check1(r);
        r=l;
        l=1;
        while(l<=r){//二分组中的第几个数 
            mid=(l+r)>>1;
            if(check2(mid)<x) l=mid+1;
            else r=mid-1;
        }
        x-=check2(r);
        ll res=l,cnt=0;
        while(res){
            ++cnt;
            res/=10;
        }
        x=cnt-x;
        for(ll i=1;i<=x;i++) l/=10;
        printf("%lld\n",l%10); 
    }
    return 0;
}

转载于:https://www.cnblogs.com/Vimin/p/11600788.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值