CF Round701-div2(CF1485)

A-Add and Divide

        题意:

        给出两个数,a和b,有两种操作,一种是a/b(计算机整除,只保留整数位),另一种是b+1,求最少通过多少次操作可以使得a==0。

        题解:

  1. BFS。
  2. (UPD:2021-02-13-17:14)可以得出对于每一步的操作,先增加b,再去除,整体会比先除在增加更优,因为 a/b > a/(b+1)。solve2()即为30ms写法。

        代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<int,PII>piii;
int t,a,b;
queue<piii>q;
void solve1(){            //93ms, 3700KB写法
    while(!q.empty()) q.pop();
        cin>>a>>b;
        q.push(mp(a,mp(b,0)));
        int cnt=0;
        while(!q.empty()){
            piii tp=q.front();q.pop();
            if(tp.fi==0){
                cout<<tp.se.se<<endl;
                break;
            }
            int cnt=tp.se.se;
            //++cnt;
            int ta=tp.fi,tb=tp.se.fi;
            q.push(mp(ta/tb,mp(tb,cnt+1)));
            q.push(mp(ta,mp(tb+1,cnt+1)));
        }
}

void solve2(){            //30ms,0KB写法
    cin>>a>>b;
    if(a==0) {
        cout<<0<<endl;
        return;
    }
    int res=a+3;
    for(int i=0;i<res;++i){
        int ans=i,bcs=a,cs=i+b;
        if(cs==1) continue;
        while(bcs) bcs/=cs,++ans;
        res=min(res,ans);
    }
    cout<<res<<endl;
}
int main(){
    cin>>t;
    while(t--)
    {
        //solve1();
        solve2();
    }
    return 0;
}

B-Replace and Keep Sorted

        题意:

        给出一串数列a,求有多少种不同的数列b,使得a与b只有一个数不同,而且b保持严格单调递增,所有数的取值区间为[1,k]。

        题解:

    • 等价于求对于原数列a,每个元素可以增加或减小的备选可能数。
    • 可以用一个新的数组来保存a中每个元素可动范围,b[i]=a[i+1]-a[i-1]-1
    • L端点的可动范围应该是1~a[L+1]-1,R端点的可动范围是a[R-1]+1~k。
    • 由于题目中每次查询都是区间查询,所以可以使用一个线段树进行维护,有因为查询区间的端点的种类数与非端点的计算方法不同,所以每次查询[L+1,R-1],然后在加上端点的种类数。

        代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define lson (rt<<1)
#define rson (rt<<1 | 1)
#define gmid (l+r >> 1)
typedef long long ll;
const int mod = 1e9+7;
int n,q,k,l,r;
int a[100500];
int b[100500];
ll sum[400500];
void pushup(int rt)
{
    sum[rt]=(sum[lson]+sum[rson]);
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=b[l];
        return;
    }
    int mid=gmid;
    build(l,mid,lson);
    build(mid+1,r,rson);
    pushup(rt);
}
int query(int l,int r,int L,int R,int rt)        //区间查询
{
    ll ans=0;
    if(L<=l && r<=R)
    {
        return sum[rt];
    }
    int mid=gmid;
    if(L<=mid) ans=(ans+query(l,mid,L,R,lson));
    if(R>mid) ans=(ans+query(mid+1,r,L,R,rson));
    return ans;
}
int main(){
    cin>>n>>q>>k;
    rep(i,1,n+1) cin>>a[i];
    rep(i,1,n+1)
        b[i]=(i==n?k+1:a[i+1])-(i==1?0:a[i-1])-2;
       build(1,n,1);
       rep(i,1,q+1){
           cin>>l>>r;
           if(l==r) cout<<k-1<<endl;
           else cout<<query(1,n,l+1,r-1,1)+a[l+1]-2+k-a[r-1]-1<<endl;
    }
    return 0;
}

C-Floor and Mod

        题意: 

        定义一对有序整数对(a,b)符合:a/b = a mod b 为特殊对,其中 a/b 为计算机整除。要求 a∈[1,x],b∈[1,y]的前提下,有多少对特殊对。

        题解:

        令 a/b = a mod b = k,则 a = b*k + k,其中b > k,缩放后:k*k ≤ b*k+k = a,所以 k ≤ x0.5,对于一个确定的k,求(a,b) 的可行对数。

        代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (long long i=a;i<n;i++)
typedef long long ll;
ll t,a,b,x,y,ans=0;
double eu=0.577215664901;
int main(){
    cin>>t;
    while(t--)
    {
        cin>>x>>y;
        for(ll i=1;i*i<x;++i) ans+=max(0ll,min(y,x/i-1)-i);
        cout<<ans<<endl;
        ans=0;
    }
    return 0;
}

D-Multiples and Power Differences

        题意:

        给出一个矩阵A,其中A的每个元素都不大于16。要求构造一个新的矩阵B,使得:

  • 使得B的行数与列数等于A
    • B中的每个元素都是A中对应元素的倍数
    • B中每个元素与其相邻元素的差,是一个四次方数,即差值等于k4,k∈N。

        题解:

    • 由于A中每个元素都不大于16,那么求一下lcm(1,...,16)=720720,让B矩阵的数全部等于720720,就解决了第二个条件。
    • 在从现有的数修改,要使得元素与四周的元素相差是一个k4,而且保持倍数关系,那就可以让四周的数等于720720,然后中间数等于720720+A(i,j)4,有一个倍数加上一个倍数,依然是这个数的倍数,然后不断插空划分之后,就得到一个类似vans棋盘格的矩阵,白点全是720720,黑点全是720720+A(i,j)4

         代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
ll ma,mb;
ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b);
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
ll cal(ll a){
    return a*a*a*a;
}
int main()
{
    cin>>n>>m;
    ll base=1;
    for(ll i=1;i<=16;++i) base=lcm(base,i);
    //cout<<base<<endl;
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=m;++j)
            cin>>ma,mb=(i+j)&1?base+cal(ma):base,cout<<mb<<' ';
        cout<<endl;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值