• P3210 [HNOI2010]取石头游戏


    题目链接

    博弈论好题!

    但是还没有完全弄懂...

    主要的思想就是判掉“上三角”的情况,因为这种情况看起来比较劣,大家会把它放最后再选,并且一定会连续地选,即“先手”选第一个和第三个,“后手”选第二个.(理性理解失败,只能感性理解)

    处理掉“上三角”以后,就可以直接从大到小选了。

    然后会发现样例都 WA 了。这是因为边界可能出现靠边的位置比较大的情况,而这时如果有偶数个,那么肯定留在最后“被迫”选择;如果有奇数个,那么最靠里的那个不会受到影响。

    值得注意的是,两边还可能出现“下三角”的情况,这时需要我们先拿走“向下”的那部分。

    代码(栈):

    signed main() {
    	read(n);
    	for (register int i = 1; i <= n; ++i) {
    		read(v[i]);
    		vis[i] = v[i] > 0;
    		if (vis[i])	++tot;
    		sum += v[i];
    	}
    	bool flag = false;
    	for (register  int i = 1; i <= n; ++i) {
    		if (!vis[i]) {
    			if (!flag) {
    				flag = true;
    				memcpy(tmp, stk, sizeof(stk));
    				memset(stk, 0, sizeof(stk));
    				top = stop; stop = 0;
    			} else {
    				while (stop)	h[++htot] = stk[stop], stop--;
    			}
    			continue;
    		}
    		stk[++stop] = v[i];
    		while (stop > 2 && stk[stop - 1] >= stk[stop] && stk[stop - 1] >= stk[stop - 2])
    			--stop, stk[stop] = stk[stop + 1] + stk[stop - 1] - stk[stop], --stop, stk[stop] = stk[stop + 1];
    	}
    	
    	
    	while (top > 1 && tmp[top] >= tmp[top - 1])	h[++htot] = tmp[top], --top;
    	if (top <= 1) {
    		while (top)	h[++htot] = tmp[top], top--;
    	} else {
    		for (register int i = 1; i + 1 <= top; i += 2) {
    			cha += (tot & 1 ? 1 : -1) * (tmp[i] - tmp[i + 1]);
    		}
    		if (top & 1)	h[++htot] = tmp[top];
    	}
    	int st = 1;
    	while (st < stop && stk[st] >= stk[st + 1])	h[++htot] = stk[st], ++st;
    	if (stop - st + 1 <= 1) {
    		while (stop >= st)	h[++htot] = stk[stop], --stop;
    	} else {
    		for (register int i = stop; i - 1 >= st; i -= 2) {
    			cha += (tot & 1 ? 1 : -1) * (stk[i] - stk[i - 1]);//Attention!!!!!
    		}
    		if ((stop - st + 1) & 1)	h[++htot] = stk[st];
    	}
    	sort(h + 1, h + 1 + htot);
    	int tp = 1;
    	for (register int i = htot; i; --i) {
    		cha += tp * h[i];
    		tp *= -1;
    	}
    	printf("%lld %lld
    ", (cha + sum) / 2, (sum - cha) / 2);
    	return 0;
    }
    

    刘队的简化版代码(双向链表):

    int main()
    {
        read(n),r[0]=1,l[n+1]=n;
        for(int i=1;i<=n;++i)
            read(v[i]),sum+=v[i],l[i]=i-1,r[i]=i+1,tag[i]=(v[i]!=0);
        for(int i=3;i<=n;i=r[i])
            while(tag[l[l[i]]]&&tag[l[i]]&&tag[i]&&v[l[i]]>=v[l[l[i]]]&&v[l[i]]>=v[i])
                v[i]=v[l[l[i]]]+v[i]-v[l[i]],r[l[l[l[i]]]]=i,l[i]=l[l[l[i]]];
        L=r[0],R=l[n+1];
        while(v[L]>=v[r[L]]&&tag[L]&&tag[r[L]]) s+=v[r[L]]-v[L],L=r[r[L]];
        while(v[R]>=v[l[R]]&&tag[R]&&tag[l[R]]) s+=v[l[R]]-v[R],R=l[l[R]];
        for(int i=L;i<=R;i=r[i])
            if(tag[i])
                v[++tot]=v[i];
        sort(v+1,v+tot+1,cmp),v[++tot]=s;
        for(int i=1;i<=tot;++i)
        {
            if(i&1) val+=v[i];
            else val-=v[i];
        }
        printf("%lld %lld",(sum+val)/2,(sum-val)/2);
        return 0;
    }
    
  • 相关阅读:
    Java 线程池
    Java 内存模型
    img图片铺满父元素
    element-ui 表单复杂数据类型校验
    element-ui 栅格布局 一行五等分
    element-ui表单只验证单个字段
    记录
    js-字符串全局替换
    vue3-搭建项目-vue2-vu3使用上的变化
    小程序引入echarts
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13438704.html
Copyright © 2020-2023  润新知