2019.2.26模拟

T1.电灯
题目描述不贴了。

这题好像有很多做法。题目还是很简单的……但是自己很菜还想了好久。
容易知道所获得的最长交错序列必然是由多个交错序列拼接的,所以只要每次枚举反转哪一个序列更新答案即可。
intlsy的做法是首先处理出来,如果想修改成交替序列有哪些位置需要被修改,之后取其中连续段更新答案。复杂度都是(O(n))

T2.比萨
题目描述不贴了。

这题比上面做法还多。有一种(O(n))的玄学做法,不会,可以问Dukelv
尺取法的做法没太懂。
我的做法是贪心+二分。一开始容易想到(O(n^2logn))的暴力,之后我们只要把二分判定过程中的贪心改成用(lowerbound)去找那个符合条件的点在哪就行。
如果不合法继续枚举断点,然后二分找中间切的位置,具体实现使用前缀和维护。复杂度(O(nlog^2n))

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('
')

using namespace std;
typedef long long ll;
const int M = 400005;

ll read()
{
	ll ans = 0,op = 1;char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
	while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
	return ans * op;
}

ll n,a[M],sum[M],L,R,ans;

bool check(ll x)
{
	rep(i,1,n)
	{
		int k = lower_bound(sum+i,sum+n+i,x+sum[i-1])-sum;
		int p = lower_bound(sum+k+1,sum+n+i,x+sum[k])-sum;
		if(sum[n+i-1] - sum[p] >= x) return 1;
	}
	return 0;
}

int main()
{
	n = read();
	rep(i,1,n) a[i] = a[i+n] = read();
	rep(i,1,n<<1) sum[i] = sum[i-1] + a[i];
	ll L = 1,R = sum[n]/3;
	while(L < R)
	{
		ll mid = (L+R+1) >> 1;
		if(check(mid)) L = mid;
		else R = mid - 1;
	}
	printf("%lld
",L);
	return 0;
}

T3.断层
这题是JOI 2016Final的T5.传送门

自己是想不出来了。
做法非常巧妙,因为斜着修改难以维护,所以我们整个将坐标轴旋转45度。(标程是顺时针但讲题时候是逆时针)
这里说逆时针旋转。这样的话,k=1的操作相当于是给定一条竖着的直线,将其左边的点向上移,k=2的操作是给定一条横着的直线,将上面的点左移。
显然可以想到用线段树/bit去维护横纵坐标。
但是正着做是不行的,因为我们无法保证单调性。我们考虑倒推,倒着做所有的操作,改变操作方向。这时候我们发现,任意一次操作必然不会改变x,y之间的相对大小。(因为一开始每个点的坐标是(i,i),横纵坐标都递增。每次我们都是把更小的纵坐标下移,更大的横坐标右移)
这样就能保证线段树/bit维护的每一个点的下标就是按照其原来的顺序排列的,直接这样倒着推回去,把坐标变换回来输出答案即可。
变换的时候坐标从((x,y))((x+y,x-y)),所以回来的时候是((frac{x+y}{2},frac{x-y}{2}))
具体的实现细节有很多,首先是旋转之后的线段长度,每个都是原来的(sqrt{2})倍,而原来每次上移1个单位相当于移动了(sqrt{2})个单位,所以要把移动长度乘以2。
再者我们令每个点表示其右面的一块土地,所以坐标是从(0~n-1)的,而且对于涉及x的操作每个也要-1.
线段树不知道为啥跑的死慢,用树状数组的时候要注意把x+1,否则容易卡死。
每次需要用二分查找你修改的区间,复杂度(O(nlog^2n))

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('
')
#define lowbit(x) x & (-x)

using namespace std;
typedef long long ll;
const int M = 400005;

int read()
{
   int ans = 0,op = 1;char ch = getchar();
   while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
   while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
   return ans * op;
}

int n,q;

struct quake
{
   int x,l,d;
}a[M];

struct tarray
{
   ll c[M];
   void add(int x,int val){x++;while(x < n+2) c[x] += val,x += lowbit(x);}
   ll ask(int x){x++;ll cur = 0;while(x) cur += c[x],x -= lowbit(x);return cur;}
   void modify(int l,int r,int val) {add(l,val),add(r+1,-val);}
}tx,ty;

int main()
{
   n = read(),q = read();
   rep(i,1,q) 
   {
      a[i].x = read(),a[i].d = read(),a[i].l = read() << 1;
      if(a[i].d == 1) a[i].x--;
   }
   rep(i,0,n) tx.modify(i,i,i),ty.modify(i,i,i);
   per(i,q,1)
   {
      if(a[i].d == 1) 
      {
	 int L = 0,R = n-1,ans = -1;
	 while(L <= R)
	 {
	    int mid = (L+R) >> 1;
	    ll k = tx.ask(mid);
	    if(k <= a[i].x) ans = mid,L = mid + 1;
	    else R = mid - 1;
	 }
	 if(ans != -1) ty.modify(0,ans,-a[i].l);
      }
      if(a[i].d == 2)
      {
	 int L = 0,R = n-1,ans = -1;
	 while(L <= R)
	 {
	    int mid = (L+R) >> 1;
	    ll k = ty.ask(mid);
	    if(k < a[i].x) L = mid + 1;
	    else ans = mid,R = mid-1;
	 }
	 if(ans != -1) tx.modify(ans,n-1,a[i].l);
      }
   }
   rep(i,0,n-1) 
   {
      ll kx = tx.ask(i),ky = ty.ask(i);
      printf("%lld
",(kx-ky)>>1);
   }
   return 0;
}

原文地址:https://www.cnblogs.com/captain1/p/10439396.html