一开始自己想贪心思路的时候想错了,导致了错误的结果。
这是我想的错误贪心思路,留在这里做个纪念吧, 写的时间还不少,
还认真去调了点bug
- /*
- 基础题意:
- 该人有一个智商q,
- 然后有n个测试,每个测试都有一个难度ai
- 编号为i的测试只能再第i天被测。
- 如果当前这个人遇到一个测试,但是这个测试的难度系数 >他的智商q,
- 那么智商q就要-1
- 我们希望能够通过的测试越多越好
- 最后输出的字符串中:
- "1"表示该测试通过
- "0"表示该测试没有通过
- */
-
- /*
- 我的贪心思路是:
- 1.判断要不要挑战比自己智商高的?
- 如果我给自己的智商-1,如果在智商 -1的 情况下,
- 比自己的(智商低并且挑战日程还在后面的)的挑战数量不变
- 那我挑战比自己智商高的就无所谓了 ,
- 反之,如果-1后,后面比自己智商低的反而挑战不了,那就抵消了,
- 没什么挑战的意义
- 2.判断要不要挑战比自己智商低的?
- 当前日子到了,遇上了就挑战呗,又不损失什么。
- */
-
-
- /*
- one case:
- 1
- 10 10
- 11 1 9 5 10 3 10 10 1 7
- ans:
- 1111111111
- myans:
- 0111111111
- 这个完全推翻了我的做法的可行性 ,
- 所以我的想法是错误的!
- */
-
-
- #include
- using namespace std;
- const int N=1e5+10;
- typedef long long LL;
- typedef pair
PLL; - LL a[N];
-
- set
s; -
-
-
- int main()
- {
- int t;
- cin>>t;
- while(t--)
- {
- int n;
- LL q;
- cin>>n>>q;
- s.clear();
-
- //智商为q
- for(int i=1;i<=n;i++)
- {
- cin>>a[i]; //各测试的难度系数为 a[i]
-
- s.insert({a[i],i});
- }
-
- string res;
- char o='1',z='0';
- for(int i=1;i<=n;i++)
- {
- s.erase({a[i],i}); //i也表示日期,到期了无论怎样都要删除,方便动态维护
- if(q<=0) break;
- if(a[i]<=q)
- {
- res+=o;
- }
- else if(a[i]>q) //考虑要不要挑战这种智商比自己高的
- {
- LL qq=q-1;
- auto it=s.lower_bound({q,0});
- auto jt=s.lower_bound({qq,0});
-
-
- if((*it).first==q&&it!=s.end())
- {
- res+=z;
- }
- else
- {
- res+=o;
- q--;
- }
-
- }
- }
-
-
- int l=res.size();
- for(int t=1;t<=n-l;t++)
- {
- res+=z;
- }
-
- cout<
size()< - cout<
-
- }
- return 0;
- }
正确做法一: 反向贪心 【把减少变成增加】
思路一:
显然,对于降智比赛,如果我们前面参加的多了那么后面的正常比赛也会变为降智比赛。所以我们的最优策略应该是当最后一天时,我们的智商值恰好为1。(参加完这天的降智比赛即为0)
所以我们,可以翻转数组,倒着模拟这种情况,从智商值为0开始,如果遇到比当前智商值大的比赛,就参加,并且智商值加一,当智商值等于Q QQ时我们便不再参加。
————————————————
版权声明:本文为CSDN博主「吃一口AC摇摇乐」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lucifer1214/article/details/125855257
- /*
- 做法一:
- */
- #include
- using namespace std;
- const int N=1e5+10;
- int a[N];
- int ans[N];
- int main()
- {
- int t;
- cin>>t;
- while(t--)
- {
- memset(ans,0,sizeof ans);
- int n,q;
- cin>>n>>q;
- for(int i=1;i<=n;i++)
- cin>>a[i];
-
- int qq=0; //当前智商为0
- for(int i=n;i>=1;i--)
- {
- if(a[i]>qq)
- {
- if(qq
- {
- qq++;
- ans[i]=1;
- }
- }
- else if(a[i]<=qq)
- {
- ans[i]=1;
- }
- }
-
-
- for(int i=1;i<=n;i++)
- {
- cout<
- }
-
- cout<
- }
-
- return 0;
- }
正确做法二:二分答案法
我们用二分法枚举答案中的1。
记住了,这里遇到之前自己常错的一个点:不能恰好等于!!!
- /*
- 做法二:二分贪心法
- 题目答案虽然是用 1和0表示的,但是也能表现出有多少个1
- (所以我们要找最多有多少1)
- 这个“最多”可以用二分法枚举 (就是找最大的)
- */
- #include
- using namespace std;
- const int N=1e5+10;
- int a[N],s[N];
- int n,q;
-
- bool check(int num) //整个序列中1的数量是num
- {
-
- int skip=n-num; //序列中0的数量也就是能跳过(可以不做)的任务数量
- int tq=q;
- for(int i=0;i
- {
- if(tq<=0) //智商值为0了,做不了了
- {
- s[i]=0;
- continue;
- }
-
-
- if(a[i]<=tq) //小于自己的智商,干就完了
- {
- s[i]=1;
- continue;
- }
- else if(a[i]>tq) //大于自己的智商,看看能不能跳过(skip>0)
- {
- if(skip>0) //如果属于跳过的,也就是可以跳过
- {
- s[i]=0;
- skip--;
- }
- else if(skip<=0)//否则就是属于要处理的"1"
- {
- if(tq>0)
- {
- s[i]=1;
- tq--;
- }
- }
- }
- }
-
-
- int co=0; //看看最终的序列中1的个数是否=num
- for(int i=0;i
- {
- if(s[i]==1)
- {
- co++;
- }
- }
-
- return co>=num; //我一开始写的恰好等于,也就是return co==num,WA了
- //之前也遇到过类似的错误,不能恰好等于
- }
-
- void solve()
- {
- cin>>n>>q;
- for(int i=0;i
- scanf("%d",&a[i]);
-
- if(q>=n) //如果q本身就大于等于n个的n
- {
- for(int i=0;i
- s[i]=1;
- }
- else
- {
- int l=0,r=n;
- while(l
- {
- int mid=(l+r+1)>>1;
- if(check(mid)) l=mid; //往右找最大的
- else r=mid-1;
- }
-
-
- //最终l是最终的结果
- //cout<<"l is "<
- check(l);
-
- }
- for(int i=0;i
- cout<
- cout<
- }
-
- int main()
- {
- int t;
- cin>>t;
- while(t--)
- {
- solve();
- }
-
- return 0;
- }
-
相关阅读:
【深度学习笔记】计算机视觉——图像增广
linux中的chmod改变权限、修改bigbig.txt文件使其所属主用户只有读权限、修改bigbig.txt文件使其所属组用户具有写权限
【Vue】组件之间的方法调用
接口测试入门
CSS中三栏布局的实现
Docker深入讲解
Leecode专题——回溯系列
揭秘得物客服IM全链路通信过程
【Spring】MyBatis(缓存机制、二级缓存、插件)面试题
如何在.NET电子表格应用程序中创建流程图
-
原文地址:https://blog.csdn.net/bei2002315/article/details/126333034