11.4离线赛

一、猴子除草

数据:对于100%,n∈[1,1e5]

显然的二分。但是只有95分。后来发现如果m==1时,直接出就有问题了,要特判掉。

二、机器人

数据:对于40%,n∈[1,100],k∈[1,5]
对于90%,n∈[1,100000],k∈[1,16]
对于100%,n∈[1,100000],k∈[1,20]

对于40%,可以直接全排所有颜色,然后再求一遍逆序对。如果进行亦凡预处理,在O(K)时间内求出逆序对的话,可以有70分。满分是对颜色K进行状压,表示前几种数用这些颜色是的最小交换次数。挺简单的。

考试时写的k^2*2^k,这个算一下复杂度只有90分,只是卡到了100分。正解是k * 2^k,同样是先预处理,把一个数i放到j里面时造成的贡献值。预处理的复杂度是一样的。

还要注意内存。这道题内存要很抠才行,开大一点点都不行。

Code:

#include<bits/stdc++.h>
#define ll long long
#define M 100005
using namespace std;
int A[M],cnt[21],lb[1<<20];
ll dp[1<<20],C[21][20],cost[21][1<<20];//开大一点就错
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)scanf("%d",&A[i]),A[i]--;
    memset(cost,0,sizeof cost);
    memset(cnt,0,sizeof cnt);
    for(int i=0;i<(1<<m);i++)dp[i]=2e10;
    for(int i=0;i<m;i++)lb[1<<i]=i,dp[1<<i]=0;
    for(int i=n-1;i>=0;i--){
        for(int j=0;j<m;j++)
            if(A[i]!=j)C[A[i]][j]+=cnt[j];
        cnt[A[i]]++;
    }
    for(int i=0;i<m;i++)//预处理
        for(int j=1;j<(1<<m);j++)
            if(j&(1<<i))continue;
            else{
                int k=j&-j;
                int x=j-k;
                cost[i][j]=cost[i][x]+C[i][lb[k]];
            }
    for(int i=0;i<(1<<m);i++)//状压
        for(int j=0;j<m;j++)
            if(i&(1<<j))continue;
            else{
                int now=i|(1<<j);
                dp[now]=min(dp[now],dp[i]+cost[j][i]);
            }
    printf("%lld\n",dp[(1<<m)-1]);
    return 0;
}

三、树上路径相交

数据:
这里写图片描述

前40分用bitset模拟就行。写的好有60分。60分其实是判断两条路径是否有交点,用LCA就行了。80分的链是按照右端点排序后直接求值。

正解和Paths很像,也是按照LCA先排序,这里按照LCA从浅到深,然后直接算值就行了。因为两个路径有交点,那么其中一个LCA肯定在另一个路径上,只所以要判断LCA上有多少个路径经过就行了。这样算也不会有重复和漏算,因为从上到下,那么上面的肯定都已经算过了。
这道题相比比第二题是要简单一点的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值