自己学校出cha的dian联zheng考jie(11.7)

T1.A

这里写图片描述

分析:
考试的时候,直接bfs(想都没想

看一下官方题解吧:
这里写图片描述

一定要仔细读题解(特别是注意柿子的系数和下标)
注意m的表达式:这里写图片描述
题解只是说要贪心的构造x,一开始我还是有点懵的
py了一下学长的代码,发现真的是贪心

注意:只有m为整数的时候才有一下的操作

我们确定了一个n之后,m中b的次方最大的就是n
我们就从b^n次方开始:tot+=m/b^n
b的次方逐次递减,不用担心m是否可以用这种方式拼出来(毕竟有b^0,不虚)

//这里写代码片
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define ll long long

using namespace std;

const int INF=1e9+7;
ll S,T,a,b,n,m;
ll ans=0;

void solve()
{
    ans=INF;
    int nn=log(T/S)/log(b);        //乘的最大次数 

    ll bb=1;                       //b^n 
    for (n=0;n<=nn;n++)            //枚举乘的次数 
    {
        ll t=T-bb*S;
        if (t<0) break;
        ll tot=0;                  //Σx 
        if (t%a==0)                //只有m是整数的时候,有下述操作 
        {
            m=t/a;
            ll bx=bb;
            while (m)
            {
                tot+=(m/bx);
                m%=bx;
                bx/=b;
            }
            ans=min(ans,tot+n);
        }
        bb*=b;
    }
}

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%lld%lld%lld%lld",&S,&T,&a,&b);
    if (S==T)
    {
        printf("0\n");
        return 0;
    }
    solve();
    if (ans==INF) printf("-1\n"); 
    else printf("%d\n",ans);
    return 0;
}

T2.B

T3.C

这里写图片描述

分析:
如果我们不考虑B
只有A一个人操作,那么事情会变成什么样呢

摆在我们面前的是一个序列
我们需要交换若干次使ta有序
这个时候,我的脑子里浮现了两个字:“置换”
还记得UVa11077这道题吗
实际上使序列有序就是一个置换
而这个置换可以看成是若干轮换的积
我们要通过乘上一些对换,使得这个置换变成n个轮换(仔细考虑一下)

也就是说,我们把当前序列变成若干轮换(一共X个)
则我们需要至少n-X次才能使序列有序
(因为长度为c的轮换需要c-1次交换)

所以我们二分一个答案mid
把B的操作都进行完之后,判断该置换需要的交换次数是否小于等于mid

一开始我打算一遍循环解决问题的,但是这样很容易就会失掉最优解

所以最保险的还是二分,并且把两个人的操作“分开”考虑

tip

二分对着样例调一调就好了,不要写死循环了
尽量不要用stl,慢的要死

//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int N=200005;
int n,a[N];
int X[N<<1],Y[N<<1],fa[N],num[N<<1],cnt[N];

int find(int x)
{
    if (fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}

int pd(int mid)
{
    for (int i=1;i<=n;i++) fa[i]=i,cnt[i]=0;
    memcpy(num,a,sizeof(num));

    for (int i=1;i<=mid;i++)
        swap(num[X[i]],num[Y[i]]);
    for (int i=1;i<=n;i++)                       //并查集维护环 
    {
        int f1=find(i);
        int f2=find(num[i]);
        if (f1!=f2) fa[f2]=f1;
    }

    int tot=0;
    for (int i=1;i<=n;i++)
    {
        int f1=find(i);
        cnt[f1]++;
    }
    for (int i=1;i<=n;i++) if (cnt[i]) tot++;
    tot=n-tot;

    if (tot<=mid) return 1;
    else return 0; 
}

int solve()
{
    int ans=0;
    int L=0; 
    int R=2*n;
    while (L<=R)
    {
        int mid=(L+R)/2;
        if (pd(mid))
            ans=mid,R=mid-1;
        else L=mid+1;
    }
    return ans;
}

int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    scanf("%d",&n);
    bool ff=1;
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]); a[i]++;
        if (a[i]!=a[i-1]+1) ff=0; 
    }
    for (int i=1;i<=2*n;i++)
        scanf("%d%d",&X[i],&Y[i]),X[i]++,Y[i]++;
    if (ff) {printf("0\n");return 0;}
    printf("%d",solve());
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值