zoukankan      html  css  js  c++  java
  • 2019.11.05(CSP模拟)(算式推导 b进制拆分+曼哈顿距离 平面几何分析+性质分析 排列 )

    根据题目可以退出这个式子:S*b^k+a*b^m = T(m<=k)。

    然后我们就可以枚举k,再倍增的使得m尽量小(k就是乘的次数,m就是加的次数)。

    时间O(log^2 T)。

    #include<bits/stdc++.h>
    #define LL long long
    #define re register
    #define INF 2100000000
    using namespace std;
    int read()
    {
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        int S=read(),T=read(),a=read(),b=read();
        LL ans=INF;
        LL n=0,nowb=1;;
        while(1)
        {
            LL tt=T-S*nowb;
            if(tt<0)break;
            if(tt%a==0)
            {
                LL m=tt/a;
                LL bb=nowb;
                LL tot=n;
                while(m)
                {
                    tot+=m/bb;
                    m%=bb;
                    bb/=b;
                }
                ans=min(ans,tot);
            }
            n++;
            nowb*=b;
        }
        if(ans==INF)printf("-1
    ");
        else printf("%lld
    ",ans);
    }
    /*
    2 3 1 2
    3 50 1 2
    1 40 4 4
    1 1000 23 2325
    1234270 100000000 20 5778
    */
    T1

     

    这道题一开始就想错了哭。

    看这样一组数据:

    8 3

    2 6

    2 7

    3 6

     

    下意识地就会觉得连3 6是最优的,那么最大长度是2。

    但是应该是连2 6,最大长度为1。(3,6)可以是从6到2再到3

    现在看正解怎么做:

    二分答案显然。

    对于一个点对(x,y)如果超过了二分的mid,一定要找到一个点对(u,v)使得|x - u| + |y - v|小于等于mid。

    这个公式就是曼哈顿距离了。

    那么我们把(x,y)和(u,v)都抽象为一个点,(u,v)要在(x,y)的曼哈顿距离内。

    如果要更改的点对的范围都有交的话return true,否则return false。

    那么如何求交呢?这里有一个小技巧。

    可以把其转化到y+x和y-x上,就变成了正着的正方形。

    然后就是求交:(lx,rx)是x的范围,(ly,ry)是y的范围。

    #include<bits/stdc++.h>
    #define LL long long
    #define N 100003
    #define INF 2100000000
    using namespace std;
    LL read()
    {
        LL x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    struct EDGE{
        int l,r,id;
    }w[N];
    int n,m;
    int b[N];
    int tot=0;
    int tmp[N],dep[N];
    pair<int,int> trans(pair<int,int> a)
    {
        return make_pair(a.first-a.second,a.first+a.second);
    }
    bool check(int mid)
    {
        int lx=-INF,rx=INF,ly=-INF,ry=INF;
        for(int i=1;i<=m;++i)
        {
            if(w[i].r-w[i].l<=mid)continue;
            pair<int,int>a=trans(make_pair(w[i].l+mid,w[i].r));
            pair<int,int>b=trans(make_pair(w[i].l-mid,w[i].r));
            lx=max(lx,b.first),rx=min(rx,a.first);
            ly=max(ly,b.second),ry=min(ry,a.second);
            if(lx>rx||ly>ry)return 0;
        }
        return 1;
    }
    int main()
    {
        freopen("b.in","r",stdin);
        freopen("b.out","w",stdout);
        n=read();m=read();
        for(int i=1;i<=n;++i)dep[i]=i;
        for(int i=1;i<=m;++i)
          w[i].l=read(),w[i].r=read(),w[i].id=i;
        int l=0,r=n+10;
        int ans;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(check(mid))ans=mid,r=mid;
            else l=mid+1;
        }
        printf("%d
    ",ans);
    }
    /*
    10 3
    1 5
    3 8
    4 10
    */
    T2

     

    因为最后要使得每个位置与位置上的数一一对应。

    我们考虑怎么使得最快达到每个位置与位置上的数一一对应。

    每次对于位置i,如果在其位置的数是a[i]而不是i,就把数字 i 换到 i 这个位置上,把a[i]换过去。

    分析一下我们可知,B操作一次A操作一次和B操作多次A再操作是等价的。(反正都是换数)。

    不如二分出B操作的次数mid,然后看换到最终结果A的操作次数会不会超过mid。

    #include<bits/stdc++.h>
    #define LL long long
    #define N 200003
    using namespace std;
    int read()
    {
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    int X[N],Y[N],a[N],b[N],vis[N];
    int n;
    bool check(int mid)
    {
        for(int i=1;i<=n;++i)a[i]=b[i];
        for(int i=1;i<=mid;++i)
          swap(a[X[i]],a[Y[i]]);
        int cnt=0;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;++i)
        {
            if(vis[i])continue;
            vis[i]=1;
            int j=i;
            while(!vis[a[j]])
            {
                cnt++;
                j=a[j];
                vis[j]=1;
            }
        }
        return cnt<=mid;
    }
    int main()
    {
        freopen("c.in","r",stdin);
        freopen("c.out","w",stdout);
        n=read();
        for(int i=1;i<=n;++i)b[i]=a[i]=read()+1;
        for(int i=1;i<=2*n;++i)
          X[i]=read()+1,Y[i]=read()+1;
        int l=0,r=N;
        int ans;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(check(mid))ans=mid,r=mid;
            else l=mid+1;
        }
        printf("%d
    ",ans);
    }
    /*
    3
    1 2 0
    1 2
    0 2
    0 0
    0 1
    0 2
    1 2
    
    3
    1 0 2
    1 2
    0 2
    0 0
    0 1
    0 2
    1 2
    */
    T3
  • 相关阅读:
    mysql复习相关
    OpenStack三种类型的NAT转换
    openstack资料相关
    [转]Web 调试工具之 Advanced REST client
    [转]Aspose.Words.dll 将 Word 转换成 html
    [Android] 开发第十天
    [win10]遇坑指南
    [转]Explorer.exe的命令行参数
    [Android] 开发第九天
    [Android] 开发第八天
  • 原文地址:https://www.cnblogs.com/yyys-/p/11800385.html
Copyright © 2011-2022 走看看