题目链接:
1.5 seconds
256 megabytes
standard input
standard output
It's Christmas time! PolandBall and his friends will be giving themselves gifts. There are n Balls overall. Each Ball has someone for whom he should bring a present according to some permutation p, pi ≠ i for all i.
Unfortunately, Balls are quite clumsy. We know earlier that exactly k of them will forget to bring their gift. A Ball number i will get his present if the following two constraints will hold:
- Ball number i will bring the present he should give.
- Ball x such that px = i will bring his present.
What is minimum and maximum possible number of kids who will not get their present if exactly k Balls will forget theirs?
The first line of input contains two integers n and k (2 ≤ n ≤ 106, 0 ≤ k ≤ n), representing the number of Balls and the number of Balls who will forget to bring their presents.
The second line contains the permutation p of integers from 1 to n, where pi is the index of Ball who should get a gift from the i-th Ball. For all i, pi ≠ i holds.
You should output two values — minimum and maximum possible number of Balls who will not get their presents, in that order.
5 2
3 4 1 5 2
2 4
10 1
2 3 4 5 6 7 8 9 10 1
2 2 题意: 这是一个带礼物的置换,只有当你给带了礼物且给你带礼物的那个人带了礼物你才能获得礼物,现在有k个人没带礼物,问最少和最多有多少人无法获得礼物; 思路: 先把这个置换写成循环的形式,对于一个长度为x的循环,现在假设其中y个没带礼物,那么最少会有y+1个人无法获得礼物,如果x==y,那么就有y个人无法获得礼物,最多有2*y个人没法获得礼物;
所以现在答案的贪心条件就明晰了;
假设这个置换可以写成num个循环,分别长为bi,那么其中一些bi的和等于k那么minans=k,or minans=k+1;这时发现是一个背包问题,可以发现bi的种类大约在sqrt(n)附近,
所以像多重背包那样把bi的数目转化成二进制的和,这样复杂度就降下来了,还有多重背包可以用单调队列优化
maxans直接贪心就好; AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,k,vis[maxn],a[maxn],b[maxn],c[maxn],d[maxn];
bool dp[maxn];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int ans1=k,ans2=0,cnt=0;
for(int i=1;i<=n;i++)
{
if(vis[i])continue;
int number=0,p=i;
while(!vis[p])
{
vis[p]=1;
number++;
p=a[p];
}
b[++cnt]=number;
}
sort(b+1,b+cnt+1);
int kk=k,num=0;
for(int i=1;i<=cnt;++i)
{
if(b[i]/2<=kk)ans2+=b[i]/2*2,kk-=b[i]/2;
else ans2+=2*kk,kk=0;
if(b[i]&1)num++;
}
ans2+=min(kk,num);
num=0;
int number=0;
for(int i=1;i<=cnt;++i)
{
if(b[i]==b[i-1])d[num]++;
else d[++num]=1,a[num]=b[i];
}
cnt=0;
for(int i=1;i<=num;++i)
{
for(int j=1;d[i];j<<=1)
{
int tep=min(d[i],j);
c[++cnt]=a[i]*tep;
d[i]-=tep;
}
}
dp[0]=true;
for(int i=1;i<=cnt;++i)
for(int j=k-c[i];j>=0;--j)
if(dp[j])dp[j+c[i]]=true;
if(!dp[k])ans1++;
printf("%d %d\n",ans1,ans2);
return 0;
}