一、猴子除草
数据:对于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上有多少个路径经过就行了。这样算也不会有重复和漏算,因为从上到下,那么上面的肯定都已经算过了。
这道题相比比第二题是要简单一点的。