2298: [HAOI2011]problem a
分析:
每个人说的话,可以转化成区间[l,r]的人的排名是一样的,于是就转化成了区间带权覆盖问题。
f[i]表示到第i个人,的最多有多少人说了真话,n-f[n]为答案。
对于f[i],如果没有线段以i为右端点,f[i] = f[i-1]。
如果有的话,那么这些线段可以选或不选,不选f[i]=f[i-1];选,它可以从最近的不想交的地方转移,找到此线段的左端点,然后f[i]=max(f[l]+min(w[l,i],i-l+1));w表示线段的权值,j-l+1,表示这条线段最大的价值。
另一种写法:f[i]表示到第i条线段的最大价值,那么可以二分找到第一个不和这条线段相交的线段,从这里转移。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cctype> 5 #include<map> 6 #include<vector> 7 #define mp(a,b) make_pair(a,b) 8 #define pa pair<int,int> 9 10 using namespace std; 11 12 const int N = 100100; 13 14 map < pa, int > w; 15 vector < int > q[N]; 16 int f[N]; 17 18 inline int read() { 19 int x = 0,f = 1;char ch=getchar(); 20 for (; !isdigit(ch); ch=getchar()) if(ch==‘-‘)f=-1; 21 for (; isdigit(ch); ch=getchar()) x=x*10+ch-‘0‘; 22 return x*f; 23 } 24 int main() { 25 int n = read(); 26 for (int i=1; i<=n; ++i) { 27 int a = read(),b = read(); 28 int l = a + 1,r = n - b; // 注意! 29 if (l > r) continue; 30 if (w[mp(l,r)] == 0) q[r].push_back(l); 31 w[mp(l,r)] ++; 32 } 33 for (int r=1; r<=n; ++r) { 34 f[r] = f[r-1]; // 不选 35 int sz = q[r].size(); 36 for (int i=0; i<sz; ++i) { 37 int l = q[r][i]; 38 f[r] = max(f[r],f[l-1]+min(w[mp(l,r)],r-l+1)); // 选 39 } 40 } 41 cout << n - f[n]; 42 return 0; 43 }
原文地址:https://www.cnblogs.com/mjtcn/p/9162109.html
时间: 2024-11-09 06:19:34