林大5.1训练赛补题

A.凸多边形曼哈顿

题意:给你一个凸多边形,问你当其中K边形的最大dis[]是多少?

思路:首先是要发现K>=4的时候答案就是定值,然后再讨论k=3,暴力找四个最远点和剩下点构成三角形。

/*
▄███████▀▀▀▀▀▀███████▄
░▐████▀▒▒▒▒▒▒▒▒▒▒▀██████▄
░███▀▒▒▒ACCEPTED▒▒▒▒▀█████
░▐██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░▐█▌▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░░█▒▄▀▀▀▀▀▄▒▒▄▀▀▀▀▀▄▒▐███▌
░░░▐░░░▄▄░░▌▐░░░▄▄░░▌▐███▌
░▄▀▌░░░▀▀░░▌▐░░░▀▀░░▌▒▀▒█▌
░▌▒▀▄░░░░▄▀▒▒▀▄░░░▄▀▒▒▄▀▒▌
░▀▄▐▒▀▀▀▀▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒█
░░░▀▌▒▄██▄▄▄▄████▄▒▒▒▒█▀
░░░░▄██████████████▒▒▐▌
░░░▀███▀▀████▀█████▀▒▌
░░░░░▌▒▒▒▄▒▒▒▄▒▒▒▒▒▒▐
░░░░░▌▒▒▒▒▀▀▀▒▒▒▒▒▒▒▐

*/

#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
const int INF=1e9+7;
const double eps=1e-6;
const int mod=1e9+7;
typedef long long ll;
typedef pair<ll,ll>p;
int x[N],y[N];
int n,a[N],ans[N];
int judge(int i,int j,int k)
{
    int sum=0;
    sum+=abs(x[i]-x[j])+abs(y[i]-y[j]);
    sum+=abs(x[i]-x[k])+abs(y[i]-y[k]);
    sum+=abs(x[k]-x[j])+abs(y[k]-y[j]);
    return sum;
}
int main() {
    int bigy=-INF,bigx=-INF,smallx=INF,smally=INF;
    cin>>n;
    for(int i=1; i<=n; i++) {
        scanf("%d%d",&x[i],&y[i]);
        bigy=max(bigy,y[i]);
        bigx=max(bigx,x[i]);
        smally=min(smally,y[i]);
        smallx=min(smallx,x[i]);
    }
    for(int i=4; i<=n; i++) {
        ans[i]=(bigx-smallx+bigy-smally)*2;
    }
    int now=0;
    for(int i=1; i<=n; i++) {
        if(x[i]==bigx)
            a[++now]=i;
        if(x[i]==smallx)
            a[++now]=i;
        if(y[i]==bigy)
            a[++now]=i;
        if(y[i]==smally)
            a[++now]=i;
    }
    sort(a+1,a+now+1);
    now=unique(a+1,a+now+1)-a-1;
    do {
        int sum=0;
        for(int i=1; i<=2; i++) {
            sum+=abs(x[a[i]]-x[a[i+1]])+abs(y[a[i]]-y[a[i+1]]);
        }
        sum+=abs(x[a[3]]-x[a[1]])+abs(y[a[3]]-y[a[1]]);
        ans[3]=max(ans[3],sum);
    } while(next_permutation(a+1,a+now+1));
    for(int i=1; i<=now; i++) {
        for(int j=i+1; j<=now; j++) {
            for(int k=1; k<=n; k++) {
                int id1=a[i],id2=a[j],id3=k;
                if(id1==id2||id1==id3||id2==id3)
                    continue;
                ans[3]=max(judge(id1,id2,id3),ans[3]);
            }
        }
    }
    for(int i=3; i<=n; i++) {
        printf("%d%c",ans[i],i==n?'\n':' ');
    }
}

E.矩阵快速幂

题意:求S = 2{m-1}×A+2{m-2}×A2+……+2{m-m}×A^m
思路:跟训练赛那题差不多,当时训练赛没过,后来也看题解了,但还是没思考为什么要那样构造矩阵,这次有点可惜,满足项之间的递推关系就能矩阵快速幂。
在这里插入图片描述
注意:矩阵2是2E,不是全2

/*
▄███████▀▀▀▀▀▀███████▄
░▐████▀▒▒▒▒▒▒▒▒▒▒▀██████▄
░███▀▒▒▒ACCEPTED▒▒▒▒▀█████
░▐██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░▐█▌▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░░█▒▄▀▀▀▀▀▄▒▒▄▀▀▀▀▀▄▒▐███▌
░░░▐░░░▄▄░░▌▐░░░▄▄░░▌▐███▌
░▄▀▌░░░▀▀░░▌▐░░░▀▀░░▌▒▀▒█▌
░▌▒▀▄░░░░▄▀▒▒▀▄░░░▄▀▒▒▄▀▒▌
░▀▄▐▒▀▀▀▀▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒█
░░░▀▌▒▄██▄▄▄▄████▄▒▒▒▒█▀
░░░░▄██████████████▒▒▐▌
░░░▀███▀▀████▀█████▀▒▌
░░░░░▌▒▒▒▄▒▒▒▄▒▒▒▒▒▒▐
░░░░░▌▒▒▒▒▀▀▀▒▒▒▒▒▒▒▐

*/

#include <bits/stdc++.h>
using namespace std;
const int N = 60 + 5;
const int INF=1e9+7;
const double eps=1e-6;
const long long mod=1e9+7;
typedef long long ll;
typedef pair<ll,ll>p;
ll x[N],y[N];
ll n,a[N][N],ans[N],m;
struct mat {
    ll mp[N][N];
    mat() {
        memset(mp,0,sizeof mp);
    }
};
mat A;
mat mul(mat A,mat B) {
    mat ans;
    for(ll i=1; i<=n*2; i++) {
        for(ll j=1; j<=n*2; j++) {
            for(ll k=1; k<=n*2; k++) {
                ans.mp[i][j]=(ans.mp[i][j]%mod+A.mp[i][k]*B.mp[k][j]%mod)%mod;
            }
        }
    }
    return ans;
}
mat Pow(mat base,ll b) {
    mat ans;
    for(ll i=1; i<=n*2; i++) {
        ans.mp[i][i]=1;
    }
    while(b) {
        //  cout<<" b= "<<b<<endl;
        if(b&1) {
            ans=mul(ans,base);
        }
        base=mul(base,base);
        b>>=1;
    }
    return ans;
}
int main() {
    scanf("%lld%lld",&n,&m);
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            scanf("%lld",&a[i][j]);
        }
    }
    mat base;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            base.mp[i][j]=base.mp[i][j+n]=a[i][j];
            if(i==j)
                base.mp[i+n][j+n]=2;
        }
    }
    mat ans;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            ans.mp[i][j]=a[i][j];
        }
    }
    for(int i=n+1; i<=n+n; i++) {
        for(int j=1; j<=n; j++) {
            if(i-n==j)
                ans.mp[i][j]=2;
        }
    }
    mat tmp=Pow(base,m-1);
    // printf("show tmp\n");
//    for(int i=1; i<=n+n; i++) {
//        for(int j=1; j<=n+n; j++) {
//            printf("%lld%c",tmp.mp[i][j]," \n"[j==n+n]);
//        }
//    }
    ans=mul(tmp,ans);
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            printf("%lld%c",ans.mp[i][j]," \n"[j==n]);
        }
    }
}
/*
1 3
1
*/

I.线段dp

题意:略。
思路:这题主要是明白为什么dp要逆推,首先我们能玩就玩的思想,可以看出来前面选还是不选会影响到后面,有后效性问题,我们假如从后往前更新就不会产生该问题,题解感觉说的很明白:
根据 dp 要求什么就设什么的伟大思想。我们直接设 dp[i]表示从 i 时刻到 n+1 时刻的空闲时间。
1.如果此时没有游戏可以玩那么 dp[i]=dp[i+1]+1 是显然的。
2.如果此时有游戏可以玩那么dp[i]=max(dp[此游戏的结束时间],dp[i])。

/*
▄███████▀▀▀▀▀▀███████▄
░▐████▀▒▒▒▒▒▒▒▒▒▒▀██████▄
░███▀▒▒▒ACCEPTED▒▒▒▒▀█████
░▐██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░▐█▌▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░░█▒▄▀▀▀▀▀▄▒▒▄▀▀▀▀▀▄▒▐███▌
░░░▐░░░▄▄░░▌▐░░░▄▄░░▌▐███▌
░▄▀▌░░░▀▀░░▌▐░░░▀▀░░▌▒▀▒█▌
░▌▒▀▄░░░░▄▀▒▒▀▄░░░▄▀▒▒▄▀▒▌
░▀▄▐▒▀▀▀▀▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒█
░░░▀▌▒▄██▄▄▄▄████▄▒▒▒▒█▀
░░░░▄██████████████▒▒▐▌
░░░▀███▀▀████▀█████▀▒▌
░░░░░▌▒▒▒▄▒▒▒▄▒▒▒▒▒▒▐
░░░░░▌▒▒▒▒▀▀▀▒▒▒▒▒▒▒▐

*/

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int INF=1e9+7;
const double eps=1e-6;
const long long mod=1e9+7;
typedef long long ll;
typedef pair<ll,ll>p;
int dpmin[N],dpmax[N],cnt[N];
struct node {
    int l,r;
    bool operator<(const node &a)const {
        if(a.l!=l)
            return a.l<l;
        return a.r<r;
    }
}a[N];
int up,n;
int main() {
    scanf("%d%d",&up,&n);
    for(int i=1; i<=n; i++) {
        scanf("%d%d",&a[i].l,&a[i].r);
        cnt[a[i].l]++;
    }
    sort(a+1,a+n+1);
    int now=0;
    for(int i=up; i>=1; i--) {
        if(cnt[i]==0) {
            dpmin[i]=dpmin[i+1]+1;
            dpmax[i]=dpmax[i+1]+1;
        } else {
            dpmin[i]=dpmin[a[++now].r];
            dpmax[i]=dpmax[a[now].r];
            for(int j=1; j<cnt[i]; j++) {
                dpmin[i]=min(dpmin[i],dpmin[a[++now].r]);
                dpmax[i]=max(dpmax[i],dpmax[a[now].r]);
            }
        }
    }
    cout<<dpmin[1]*4+dpmax[1]*3<<endl;
    //cout<<dpmin[1]<<"  "<<dpmax[1]<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值