jxoi2017
题解:
并不知道题目顺序就按照难度排序了
[JXOI2017]加法
这是一道很简单的贪心
最小值最大二分答案
然后我们可以从左向右考虑每一个位置
如果他还需要+A
我们就从能覆盖它的区间中挑一个最右的
正确性比较显然
暴力是n^2logn*T的 可能比较虚
会发现覆盖操作可以用线段树维护,查询最右可以使用堆
n*logn^2*T
[JXOI2017]颜色
写的复杂了。。
正解比较简单
枚举右端点i,确定左端点j的可行位置
我们会发现,
对于maxv<=i,那么maxv>=j>=minv是不可行的
对于maxv>i,那么1<=j<=minv是不可行的
于是问题就变成了区间+1,区间-1,查询为0的个数
网上好像都是利用这个是1-x的所以变成从左到右枚举然后优先队列解决的
其实我们可以通过维护最小值个数,最小值来直接实现
我的方法是对于每一种颜色
我们可行的方案是在两个颜色空当之中,或者1个在最左边,1个在最右边
于是问题变成了n次覆盖一个矩形,最后查询矩形中为k的个数(其实查为0就和上面一样了)
注意区间2-1这样的是不符合的 所以可以先给不符合的-1
然后我们可以利用扫描线+线段树解决
// luogu-judger-enable-o2 #include <bits/stdc++.h> using namespace std; #define ll long long #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) #define me(x) memset(x,0,sizeof(x)) #define mid ((h+t)/2) char ss[1<<24],*A=ss,*B=ss; IL char gc() { return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; } template<class T>IL void read(T &x) { rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48); while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; } const int N=4e5+10; const int N2=N*4; int cnt; struct re{ int a,b,c,d; }p[N*5]; int maxa[N2],lazy[N2],data[N2],a[N]; vector<int> ve[N]; IL void change(int h1,int t1,int h2,int t2,int k) { p[++cnt].a=h1,p[cnt].b=h2,p[cnt].c=t2,p[cnt].d=k; p[++cnt].a=t1+1,p[cnt].b=h2,p[cnt].c=t2,p[cnt].d=-k; } IL bool cmp(re x,re y) { return(x.a<y.a); } void build(int x,int h,int t) { maxa[x]=0; data[x]=t-h+1; lazy[x]=0; if (h==t) return; build(x*2,h,mid); build(x*2+1,mid+1,t); } int cnt2=0; void insert(int x,int h,int t,int h1,int t1,int k) { if (h1>t1) return; if (h1<=h&&t<=t1) { maxa[x]+=k; lazy[x]+=k; return; } if (lazy[x]) { maxa[x*2]+=lazy[x]; maxa[x*2+1]+=lazy[x]; lazy[x*2]+=lazy[x]; lazy[x*2+1]+=lazy[x]; lazy[x]=0; } if (h1<=mid) insert(x*2,h,mid,h1,t1,k); if (mid<t1) insert(x*2+1,mid+1,t,h1,t1,k); int t11=maxa[x*2],t22=maxa[x*2+1]; if (t11<t22) maxa[x]=t22,data[x]=data[x*2+1]; else if (t11>t22) maxa[x]=t11,data[x]=data[x*2]; else maxa[x]=t11,data[x]=data[x*2+1]+data[x*2]; } int main() { int T,n; read(T); rep(ttt,1,T) { read(n); rep(i,1,n) ve[i].clear(); int m=0; rep(i,1,n) { read(a[i]); m=max(a[i],m); ve[a[i]].push_back(i); } int k=m; cnt=0; rep(i,1,m) { if (!ve[i].size()) { k--; continue; } change(1,ve[i][0],ve[i][ve[i].size()-1],n,1); int tmp=(int)(ve[i].size())-2; rep(j,0,tmp) change(ve[i][j]+1,ve[i][j+1]-1,ve[i][j]+1,ve[i][j+1]-1,1); change(1,ve[i][0]-1,1,ve[i][0]-1,1); change(ve[i][ve[i].size()-1]+1,n,ve[i][ve[i].size()-1]+1,n,1); } rep(i,2,n) { change(i,i,1,i-1,-1); } sort(p+1,p+cnt+1,cmp); ll ans=0; build(1,1,n); rint j=1; rep(i,1,n) { while (j<=cnt&&p[j].a<=i) insert(1,1,n,p[j].b,p[j].c,p[j].d),j++; if (maxa[1]==k) ans+=data[1]; } printf("%lld\n",ans); } return 0; }