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\n");
    else printf("%lld\n",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\n",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\n",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
posted @ 2019-11-05 18:22  yyys  阅读(168)  评论(0编辑  收藏  举报