AtCoder Regular Contest 100

C : 排序
D : 贪心
E : 二进制+前缀和
F : Unfinished

我晚上只是想来填一下高考志愿的,突然发现AtCoder有比赛,马上点进去就开始了…
因为刚校选完不太想再打,于是养生地做完了C,离开比赛玩了一会儿,再打开准备做D和E,发现时间可能不太够就选分大的E做完就继续去玩了…


###C - Linear Approximation

显然把 A i A_i Ai 改成 A i − i A_i-i Aii 然后取中位数当 b b b 就是答案了。
想不到吧,本弱我还WA了一发。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define cmax(_i,_j) ((_i)<(_j)?(_i)=(_j):0)
    #define cmin(_i,_j) ((_i)>(_j)?(_i)=(_j):0)
    #define N 200005
    using namespace std;
    namespace runzhe2000
    {
    	int n, a[N];
    	void main()
    	{
    		scanf("%d",&n);
    		for(int i = 1; i <= n; i++) scanf("%d",&a[i]), a[i] -= i;
    		sort(a+1, a+1+n); int x = a[n/2+1]; long long ans = 0;
    		for(int i = 1; i <= n; i++) ans += abs(x-a[i]);
    		printf("%lld\n",ans);
    	}
    }
    int main()
    {
    	runzhe2000::main();
    }

####D - Equal Cut

枚举第二个切点。那么现在考虑左右两边怎么切。显然两边切起来分别相差越小越好。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define cmax(_i,_j) ((_i)<(_j)?(_i)=(_j):0)
    #define cmin(_i,_j) ((_i)>(_j)?(_i)=(_j):0)
    #define N 200005
    using namespace std;
    namespace runzhe2000
    {
    	typedef long long ll;
    	int n; ll a[N], ans = 1ll<<60;
    	void main()
    	{
    		scanf("%d",&n);
    		for(int i = 1; i <= n; i++) scanf("%lld",&a[i]), a[i] += a[i-1];
    		
    		int l = 1, r = 3;
    		
    		for(int i = 2; i < n-1; i++)
    		{
    			for(; l + 1 < i && abs(a[i]-2*a[l+1]) < abs(a[i]-2*a[l]); l++);
    			for(; r + 1 < n && abs(a[n]-a[r+1]-a[r+1]+a[i]) < abs(a[n]-a[r]-a[r]+a[i]); r++);
    			cmin(ans, max(max(a[l],a[i]-a[l]),max(a[r]-a[i], a[n]-a[r]))-min(min(a[l],a[i]-a[l]),min(a[r]-a[i], a[n]-a[r])));
    		}
    		printf("%lld\n",ans);
    	}
    }
    int main()
    {
    	runzhe2000::main();
    }

####E - Or Plus Max

这题好像被我想复杂了呀…
我的做法:考虑对下标建出trie树。考虑一个询问x,答案是i,j。要么i or j = x,要么一定存在一位,满足i的这一位or j的这一位是0,而x的这一位是1。相当于在trie图上放两个指针跑。若x这一位是0,那么两个指针只能进0边,否则都能进,都进复杂度就不太对。那么重新定义trie图,把0边的信息全部复制到1边的信息里,这样x这一位是1就只要进1边(等价于0边1边都进)。最后xjb判一判。
题解的做法:很简洁…考虑i or j恰好是x的子集,这个答案容易贡献,当然不能枚举子集,对二进制位作前缀和即可。然后这个答案的前缀和就是要求的了…妙…

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define cmax(_i,_j) ((_i)<(_j)?(_i)=(_j):0)
    #define cmin(_i,_j) ((_i)>(_j)?(_i)=(_j):0)
    #define N (1<<19)
    using namespace std;
    namespace runzhe2000
    {
    	int n, a[N];
    	
    	int nodecnt;
    	struct node
    	{
    		node *ch[2];
    		int mx1, mx2, dep;
    		node(){ch[0]=ch[1]=NULL;mx1=mx2=0;}
    	}s[N*20];
     
    	struct TRIE
    	{
    		node *root;
    		void init()
    		{
    		    root = &s[++nodecnt];
    		    root->dep = n;
    		}
    		void insert(int x)
    		{
    		    node *p = root;
    		    for(int pos = 1<<(n-1), i = n-1; pos; pos>>=1, i--)
    		    {
    		        if(!p->ch[0])p->ch[0]=&s[++nodecnt], p->ch[0]->dep = i;
    		        if(!p->ch[1])p->ch[1]=&s[++nodecnt], p->ch[1]->dep = i;
    		        int son = x&pos?1:0;
    		        p=p->ch[son];
    		        if(a[x] >= p->mx1) p->mx2 = p->mx1, p->mx1 = a[x];
    		        else if(a[x] > p->mx2) p->mx2 = a[x];
    		    }
    		}
    		void dfs2(node *l, node *p)
    		{
    			if(l->mx1 >= p->mx1) p->mx2 = p->mx1, p->mx1 = l->mx1;
    		    else if(l->mx1 > p->mx2) p->mx2 = l->mx1;
    			if(l->mx2 >= p->mx1) p->mx2 = p->mx1, p->mx1 = l->mx2;
    		    else if(l->mx2 > p->mx2) p->mx2 = l->mx2;
    		    
    			if(l->dep == 0) return;
    		    
    		    dfs2(l->ch[0],p->ch[0]);
    		    dfs2(l->ch[1],p->ch[1]);
    		}
    		void dfs(node *p)
    		{
    			if(p->dep == 0) return;
    			dfs(p->ch[0]);
    			dfs(p->ch[1]);
    			dfs2(p->ch[0],p->ch[1]);
    		}
    		void build()
    		{
    			dfs(root);
    		}
    		int solve(int x)
    		{
    			node *p = root;
    			
    			int ans = 0;
    			
    		    for(int i = n-1; ~i; i--)
    		    {
    		    	if((x>>i)&1)
    		    	{
    		    		
    		  			cmax(ans, p->ch[0]->mx1+p->ch[0]->mx2);
    		   			
    		   			p = p->ch[1];
    		    	}
    		    	else p = p->ch[0];
    		    }
    		    
    		    cmax(ans, p->mx1+p->mx2);
    			
    			return ans;
    		}
    	}T;
     
    	
    	void main()
    	{
    		scanf("%d",&n);T.init();
    		for(int i = 0, ii = 1<<n; i < ii; i++) scanf("%d",&a[i]), T.insert(i);
    		T.build();
    		for(int i = 1, ii = 1<<n; i < ii; i++) printf("%d\n",T.solve(i));
    	}
    }
    int main()
    {
    	runzhe2000::main();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值