这道题会根据a数组直接对a[i]进行操作,可能与前面交换,可能位置不变。
然后要你求出每个值最小和最大的位置
都说做题前要分析,但是我看了几遍还是没想到用什么算法简单
但其实是我不会分析
因为模拟也是种做法,并且按题意模拟的话,也不过是遍历a数组的操作,仅仅O(m)的复杂度而已。这就是想复杂了,要把模拟加入考虑,并且判断复杂度能不能过
#include<iostream> #include<string.h> #include<stdio.h> using namespace std; const int maxn=1e5+7; int n,m,a[maxn*4],l[maxn],h[maxn],num[maxn],pos[maxn]; ///数字i的位置是pos[i],位置i的数字是num[i] int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) l[i]=h[i]=num[i]=pos[i]=i; for(int i=1;i<=m;i++){ int psi=pos[a[i]]; if(psi==1)continue; int t=num[psi-1];///t是前一个位置的数字 pos[a[i]]=psi-1; pos[t]=psi; num[psi]=t; num[psi-1]=a[i]; l[a[i]]=min(l[a[i]],psi-1); h[t]=max(h[t],psi); } for(int i=1;i<=n;i++) cout<<l[i]<<' '<<h[i]<<endl; return 0; }
这道题明显是个二分啊
先确定屋子的大小,然后尽量把a或c单独放一个屋子
如果有一个屋子最后还是同时放了a和c,那就失败
#include<iostream> #include<string.h> #include<stdio.h> using namespace std; int ce,a,b,c; bool check(int mid){ if(a>mid&&c>mid)return false; if(a<=mid&&c<=mid)return true; if(a>mid) return a<=mid*2; if(c>mid) return c<=mid*2; } int main(){ scanf("%d",&ce); while(ce--){ scanf("%d%d%d",&a,&b,&c); int l=(a+b+c-1)/3+1,r=max(a,max(b,c)),ans; while(l<=r){ int mid=(l+r)>>1; if(check(mid)){ ans=mid; r=mid-1; } else l=mid+1; } printf("%d\n",ans); } return 0; }
总结我一个常见错误——就是我常用++,--,+=,-=,然后就会在多次判断的题里WA
这道题题意是选择车厢大小s,保证s每次至少能装一个队最多装两个队,然后运r次运完
得到的花费s*r最小
我前面做了一道二分,然后看这道题也像二分
不过明显这道题判断条件不是成功与否,而是花费多少
所以我果断地选择了三分答案,让LR逼近花费少的答案,然后WA
为什么会WA呢,因为我即使能通过知道s算出需要的花费,但是没考虑到花费并不与s成单调关系
比如3 2 3 用3的车厢运3次花费9,而4的车厢运3次花费12,5的车厢运两次花费10
所以三分是不行的(虽然也过了20多个样例)
然后看了题解,这道题应该是贪心
贪心策略是尽量把人数多的队和人数少的队放一起,使每个车厢的人差不多,然后把人数特别多的队单独放一个车厢。理想状态是有多少人就花费多少
#include<iostream> #include<string.h> #include<stdio.h> #include<algorithm> using namespace std; const int maxk=8007; const int inf=0x7fffffff; int n,m,k,pep[maxk],maxroom; int main(){ scanf("%d%d",&n,&k); for(int i=0;i<n;i++){ scanf("%d",&m); pep[m]++; } sort(pep+1,pep+1+k); if(k==1)maxroom=pep[1]; else{ for(int i=1,j=k;j-i>=1;i++,j--) maxroom=max(maxroom,pep[i]+pep[j]); } int ans=inf; for(int i=pep[k];i<=maxroom;i++){ int l=1,h=k,r=0; while(l<=h){ if(pep[l]+pep[h]<=i) l++,h--; else h--; r++; } ans=min(ans,i*r); } printf("%d\n",ans); return 0; }
给出1到N的身高的人的个数,想排成k排,每排的身高最低最高差距不大于1,每排人数一样,问最多参与排队的人的个数
我就是做了这道和上上道都是二分,然后才以为是专题,然后用二分做上道题的
这道题用二分,先确定一排的人数,然后看这样排能不能排,然后得到k排条件下,一排最多的人数
#include<iostream> #include<string.h> #include<stdio.h> using namespace std; typedef long long LL; const int maxn=3e4+7; int ce,n; LL k,c[maxn],sum,l,r,ans; bool check(LL mid){ LL numk=0,lef=0; for(int i=1;i<=n;i++){ LL t=(lef+c[i])/mid; numk+=t; if(numk>=k)return true; lef=lef>=t*mid?c[i]:c[i]+lef-t*mid; } return false; } int main(){ scanf("%d",&ce); while(ce--){ scanf("%d%lld",&n,&k); sum=0; for(int i=1;i<=n;i++){ scanf("%lld",&c[i]); sum+=c[i]; } l=1,r=sum/k,ans=-1; while(l<=r){ LL mid=(l+r)>>1; if(check(mid)){ ans=mid; l=mid+1; } else r=mid-1; } printf("%lld\n",ans!=-1?ans*k:0); } return 0; }
个人认为是道综合性很强的图论。虽然看别人题解说是简单图论,可是代码还是很老实的...
要对构造图很了解才行
这个线段树就更没看懂了,先mark一下吧