【HAOI2011】problem a

我的思维能力真的上来了好感动555

原题:

随便点的一道DP题,本来这题以前无数次想不出来,题解好像也看不懂,想的时候都打算放弃了

但是想着一定要死磕思维能力,最后居然还真的自己做出来了

果真是以前放弃得太轻易hhh

首先要确定一下题意,“有ai个人”我感觉也可以理解为>=ai个人

但是其实后来想一下,如果这样说得话就没必要强调可能有相同分数了

因为如果是>=ai的话,两个同分的和两个相邻分数的对于合法性其实都一样

所以认为题意为恰好有ai个人(当然考场上还是大力问监考)

那么研究一下这个约束条件的限制,可以发现实际上是ai和bi中间摞了n-ai-bi个人

那么用xi=ai表示这一摞人前面有多少人,yi=n-ai-bi表示摞了多少人

可以发现对于xi相等而yi不等的两个人一定无法满足

而xi和yi都相等的人一定一起满足(除非xi和yi相等的人数超过了yi,那么多出者不满足)

所以可以把xi和yi相等的人合并,令zi表示满足这些人的要去需要再拿多少个假人充数

(假人就是条件不被满足的人)

然后灵稽一动,不妨就按xi递增排序,然后考虑枚举到的每个人是否满足要求

如果这样做的话状态可以设为f[i]表示把前i个人安排上需要的最少说谎人数

递推求解

这样好像不太对,有后效性

即假设现在要那一个假人充数,那这个假人是前面考虑过的,还是后面没考虑的,还是把已经满足的撤了

你不知道,会影响决策

我的思路转了一圈之后,找不到什么有可能的做法,再回来研究这样做,发现各种细节美好得不正常

于是决定随便写写试试

然后就ac了

我尻 这都行

现在再来考虑算法得正确性,可以发现刚才得顾虑是多余的

因为所有没满足要求的假人都是一样的,而易证假人是充足的,因为如果假人不够则与总人数冲突

所以我们完全不用考虑假人从哪来,只需要直到前边已经有i个人被安排了就行

最后整理一下思路

首先令xi=ai,yi=n-ai-bi,zi=需要补的假人

然后按xi递增排序,走递推

f[i]初值为i,包括f[0]=0

递推公式为f[a[i].x+a[i].y]=min(f[a[i].x+a[i].y],f[a[i].x]+a[i].z)

需要注意a[i].x和a[i-1].x中间可能隔了几个数,而这些状态实际受f[a[i-1].x]的影响

因为中间可以直接丢一个假人过去把之前的更优决策继承过来

也就是说f[a[i-1].x+j]应该等于f[a[i-1].x]+j,f[a[i].x]应该等于min(f[a[i].x],f[a[i-1].x]+a[i].x-a[i-1].x)

我的写法是用一个temp跟着a[i].x走,每次让temp++就令f[temp]=min(f[temp],f[temp-1]+1)

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 struct nds{int x,y,z;}a[110000],b[110000];  int m=0;
 6 int n;
 7 int f[110000];
 8 bool cmp(nds x,nds y){  return x.x==y.x ? x.y<y.y : x.x<y.x;}
 9 int main(){
10     freopen("ddd.in","r",stdin);
11     cin>>n;
12     int l,r;
13     for(int i=1;i<=n;++i){
14         scanf("%d%d",&l,&r);
15         a[i].x=l,a[i].y=n-l-r;
16     }
17     sort(a+1,a+n+1,cmp);
18     for(int i=1;i<=n;++i)if(a[i].y>0){
19         if(a[i].x!=b[m].x || a[i].y!=b[m].y){
20             b[++m]=a[i];
21             b[m].z=a[i].y-1;
22         }
23         else  b[m].z=(b[m].z ? b[m].z-1 : 0);
24     }
25     for(int i=1;i<=n;++i)  f[i]=i;
26     f[0]=0;
27     int tmp=0;
28     for(int i=1;i<=m;++i){
29         while(tmp<b[i].x){
30             ++tmp;
31             f[tmp]=min(f[tmp],f[tmp-1]+1);
32         }
33         f[b[i].x+b[i].y]=min(f[b[i].x+b[i].y],f[b[i].x]+b[i].z);
34     }
35     while(tmp<n){
36         ++tmp;
37         f[tmp]=min(f[tmp],f[tmp-1]+1);
38     }
39     printf("%d\n",f[n]);
40     return 0;
41 }

原文地址:https://www.cnblogs.com/cdcq/p/12024283.html

时间: 2024-08-02 21:13:39

【HAOI2011】problem a的相关文章

bzoj2301【HAOI2011】Problem b

2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MB Submit: 2951  Solved: 1318 [Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Ou

【BZOJ2301】【HAOI2011】Problem b [莫比乌斯反演]

Problem b Time Limit: 50 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Output 共n行,每行一个整数表示满足要求的数对(x,y)的个数. Sample Inp

BZOJ 2301 【HAOI2011】 Problem b

Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Output 共n行,每行一个整数表示满足要求的数对(x,y)的个数 HINT 100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000 过了这么久终于写出了莫比乌斯反演的入门题TAT-- 这道

【BZOJ2298】【HAOI2011】problem a 动态规划

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44979323"); } 题解: 一句话 (a,b) 可以理解成一个线段 (a,n?b] . 然后排个序去下重,最后一个线段的权值 x 就是表示 这 x 人互不冲突,一起算. 然后动态规划求若干条不相交线段的权值最大值,最后用总人数减

【HAOI2011】向量

题目描述: 给你一对数a,b,你可以任意使用(a,b), (a,-b), (-a,b), (-a,-b), (b,a), (b,-a), (-b,a), (-b,-a)这些向量,问你能不能拼出另一个向量(x,y). 说明:这里的拼就是使得你选出的向量之和为(x,y) 输入格式: 第一行数组组数t,(t<=50000) 接下来t行每行四个整数a,b,x,y (-2*10^9<=a,b,x,y<=2*10^9) 输出格式: t行每行为Y或者为N,分别表示可以拼出来,不能拼出来 分析: 我们看

【BZOJ2998】Problem A(动态规划)

[BZOJ2998]Problem A(动态规划) 题面 BZOJ 题解 一个人的成绩范围可以确定为一个区间 这样就变成了 选择若干区间,不重合, 每个区间有个权值,求最大权值和 这样就可直接\(dp\)了 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #includ

【bzoj2298】【HAOI2011】【problem a】

2298: [HAOI2011]problem a http://www.lydsy.com/JudgeOnline/problem.php?id=2298 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 696 Solved: 307 [Submit][Status][Discuss] Description 一次考试共有n个人参加,第i个人说:"有ai个人分数比我高,bi个人分数比我低."问最少有几个人没有说真话(可能有相同的分数)

【bzoj2298】【HAOI2011】【problem a】【dp】

Description 一次考试共有n个人参加,第i个人说:"有ai个人分数比我高,bi个人分数比我低."问最少有几个人没有说真话(可能有相同的分数) Input 第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai.bi Output 一个整数,表示最少有几个人说谎 Sample Input 3 2 0 0 2 2 2 Sample Output 1 HINT 100%的数据满足: 1≤n≤100000 0≤ai.bi≤n 思路:其实我们可以很巧妙的把这道题转化

【bzoj2302】【HAOI2011】【problem c】【dp】

Description 给n个人安排座位,先给每个人一个1~n的编号,设第i个人的编号为ai(不同人的编号可以相同),接着从第一个人开始,大家依次入座,第i个人来了以后尝试坐到ai,如果ai被占据了,就尝试ai+1,ai+1也被占据了的话就尝试ai+2,--,如果一直尝试到第n个都不行,该安排方案就不合法.然而有m个人的编号已经确定(他们或许贿赂了你的上司-),你只能安排剩下的人的编号,求有多少种合法的安排方案.由于答案可能很大,只需输出其除以M后的余数即可. Input 第一行一个整数T,表示