• (HN)AHOI2018 转盘


    题意:

    (n) 个格子围成一圈,每个格子里有一个物品,每个物品的出现时间为 (T_i) 。开始时选择一个格子为起点,每个单位时间可以向前走一格或不动,若当前格的物品已出现则将其标记。有 (m) 次修改,每次修改一个物品的出现时间,并询问将所有物品标记的最短时间。

    题解:

    猜一下一个最优方案:选择一个点后停留一段时间后直接走一圈标记所有物品。感性分析一下是对的,因为多走超过一圈的地方可以用等待来代替。具体分析或证明可以看其他神仙的博客。

    那么得到柿子:

    [ans=displaystyle min _{i=1}^n { max_{j=i}^{i+n-1} {T_j-(j-i)}}+n-1 ]

    (前者为最大等待时间)。

    整理一下柿子,设 (a_j=T_j-j)

    [ans=displaystyle min _{i=1}^n { max_{j=i}^{i+n-1} {a_j}+i}+n-1 ]

    我们发现对于 ([i+ n,2n]) 的答案显然不会更优,所以我们减少一下限制,即:

    [ans=displaystyle min _{i=1}^n { max_{j=i}^{2n} {a_j}+i}+n-1 ]

    发现最后对答案可能产生贡献的点的 (a_j) 一定从右到左单增。

    于是我们直接用线段树维护区间最大值和 (min_{i=l}^{r/2}{max_{j=l}^{r}{a_j}+i})即可,即维护一个单调栈。时间复杂度为 (O(mlog^2 n)) .

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int gi()
    {
    	char c; int x=0;
    	for(;c<'0'||c>'9';c=getchar());
    	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
    	return x;
    }
    const int N=200005;
    int n,m,p,ans,t[N],st[N<<2],mx[N<<2];
    #define lx (x<<1)
    #define rx (x<<1|1)
    int query(int x, int l, int r, int w)
    {
    	if(l==r) return l+max(w,mx[x]);
    	int mid=l+r>>1;
    	if(mx[rx]>=w) return min(st[x],query(rx,mid+1,r,w));
    	return min(mid+1+w,query(lx,l,mid,w));
    }
    void pushup(int x, int l, int r)
    {
    	int mid=l+r>>1;
    	mx[x]=max(mx[lx],mx[rx]);
    	st[x]=query(lx,l,mid,mx[rx]);
    }
    void build(int x, int l, int r)
    {
    	if(l==r)
    	{
    		mx[x]=t[l],st[x]=t[l]+l;
    		return ;
    	}
    	int mid=l+r>>1;
    	build(lx,l,mid),build(rx,mid+1,r);
    	pushup(x,l,r);
    }
    void update(int x, int l, int r, int s)
    {
    	if(l==r)
    	{
    		mx[x]=t[l],st[x]=t[l]+l;
    		return ;
    	}
    	int mid=l+r>>1;
    	s<=mid?update(lx,l,mid,s):update(rx,mid+1,r,s);
    	pushup(x,l,r);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("circle.in","r",stdin);
    	freopen("circle.out","w",stdout);
    #endif
    	n=gi(),m=gi(),p=gi();
    	for(int i=1;i<=n;++i) t[i]=gi()-i,t[i+n]=t[i]-n;
    	build(1,1,n<<1);
    	printf("%d
    ",ans=st[1]+n-1);
    	while(m--)
    	{
    		ans*=p;
    		int x=gi()^ans,y=gi()^ans;
    		t[x]=y-x,t[x+n]=t[x]-n;
    		update(1,1,n<<1,x),update(1,1,n<<1,x+n);
    		printf("%d
    ",ans=st[1]+n-1);
    	}
    }
    
    
  • 相关阅读:
    python3 解决tcp黏包方法一
    python3 udp不黏包但丢数据
    python3 类的单例模式
    python3 day07 练习题
    python3 tcp黏包情况二
    python3 tcp黏包情况一
    python3 subprocess模块
    python3 UDP协议下的socket
    python3 TCP协议下的socket
    python3 socket网络通信的整个流程
  • 原文地址:https://www.cnblogs.com/farway17/p/10423461.html
Copyright © 2020-2023  润新知