现在的位置: 首页 > 综合 > 正文

Codeforces Round #225 (Div. 1)

2014年08月29日 ⁄ 综合 ⁄ 共 4723字 ⁄ 字号 评论关闭

A:

从最左边向右的牛,和最右边向左的牛中取影响最小的先挤奶。一直比下去。

code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
    
#define N  200010
#define ll long long
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int MOD   =1000000007;
const double EPS=1e-7;

int n;
int a[N],l[N],r[N];

int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++){
		l[i]+=l[i-1]+(a[i]==0);
		r[i]+=r[i-1]+(a[i]==1);
	}
	int L,R;
	for(int i=1;i<=n;i++) if(a[i]==1){
	   	L=i;
		break;
	}
	for(int i=n;i>=1;i--) if(a[i]==0){
	   	R=i;
		break;
	}
	ll ans=0;
	for(int i=L,j=R;i<j;){
		while(i<=n && a[i]!=1) i++;
		while(j>=1 && a[j]!=0) j--;
		if(i>=j || i==n+1 || j==0) break;
		ans+=min(l[j]-l[i],r[j]-r[i-1]);
		if(l[j]-l[i]<r[j]-r[i-1]) i++;
		else j--;
	}
	cout<<ans<<endl;
	return 0;
}

B:

这题应该改成D题的。。。总感觉这场难度顺序放错了。。


这题的做法是这样的。


黄点是人在的位置,蓝点是不可经过的点。

对于(x,y)这个蓝点,如果在它右边的Y+1的地方,x-1及以下的位置有蓝点的话,那么这两个蓝点就能形成一条封锁线。

封锁线以下的区域是不可能走到的(即灰色段)。如果封锁线组成的分锁链能完全分隔(1,1)和(n,n)那么就无法到达,否则答案必然是2*n-2。

封锁线可以用有向边表示。

所以我们从左下的蓝点开始,从左往右连,从下往上连,到右上的蓝点。如果存在那么一条路径,能从左下的蓝点走到右上的蓝点,那么说明能分隔开。这里的左下指的是(x==n || y==1),右上(x==1 || y==n),必须是这样在左下边界的蓝点走到右上边界的蓝点才能完全分隔开(1,1)和(n,n)。

上面说的是以y坐标为基准的情况,x的也类似处理。


最后封锁链可能类似这样:



图画的丑了点。。。不喜勿喷。。。

code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
    
#define N  100010
#define ll long long
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int MOD   =1000000007;
const double EPS=1e-7;

map<int,set<PI > > line[2];
vector<int> e[N];
bool vis[N];

void dfs(int u){
	vis[u]=true;
	for(int i=0;i<e[u].size();i++) 
		if(!vis[e[u][i]]) dfs(e[u][i]);
}

void solve(int op){
	map<int,set<PI > >::iterator i;
	set<PI >::iterator j,k;
	for(i=line[op].begin();i!=line[op].end();i++){	
		int cur=i->first;
		for(j=line[op][cur].begin();j!=line[op][cur].end();j++){
			set<PI > &next=line[op][cur+1];
			k=next.lower_bound((PI){j->first-1,0});
			if(k!=next.end()){
				if(op==0) // down to up
					e[k->second].push_back(j->second);
				else	//left to right
					e[j->second].push_back(k->second);
			}
		}
	}
}

int main(){
	int n,m,s=0,t;
	scanf("%d%d",&n,&m);
	t=m+1;
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		line[0][x].insert((PI){y,i});
		line[1][y].insert((PI){x,i});
		if(x==n || y==1) e[t].push_back(i);
		if(x==1 || y==n) e[i].push_back(s);
	}
	solve(0); 
	solve(1);
	dfs(t);
	if(vis[s]) puts("-1");
	else printf("%d\n",2*n-2);
	return 0;
}

C:

显然增加一个点的val,深度和它同奇偶的子树中的点也会+val,非同奇偶的则-val。

然后时间戳重标记树,维护奇偶两个树状数组,区间更新,点查询即可。


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
    
#define N  200010
#define ll long long
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int MOD   =1000000007;
const double EPS=1e-7;

class BIT{
public:
	int n,sum[N];

	void init(int n){
		this->n=n;
		fill(sum+1,sum+n+1,0);
	}

	void add(int i,int x){
		for(;i>=1;i-= -i&i){
			sum[i]+=x;
		}
	}

	void update(int l,int r,int x){
		if(r<l) return ;
		add(l-1,-x);
		add(r,x);
	}
	
	int query(int i){
		int ans=0;
		for(;i<=n;i+= -i&i){
			ans+=sum[i];
		}
		return ans;
	}
}T[2];

int val[N],l[N],r[N],h[N],Time;
vector<int> e[N];

void dfs(int u,int far,int step){
	l[u]=++Time;
	h[u]=step;
	for(int i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(v==far) continue;
		dfs(v,u,step+1);
	}
	r[u]=Time;
}

int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",val+i);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1,-1,0);
	T[0].init(n);
	T[1].init(n);
	while(m--){
		int op,x,c;
		scanf("%d%d",&op,&x);
		if(op==1){
			scanf("%d",&c);
			T[h[x]%2].update(l[x],r[x],c);
			T[(h[x]%2)^1].update(l[x],r[x],-c);
		}else{
			int ans=T[h[x]%2].query(l[x])+val[x];
			printf("%d\n",ans);
		}
	}
	return 0;
}

D:

dp[i][val] 表示以第i个数结尾,构造出的和为val的方案数。

ans=sum{dp[i][0] }

每次转移后,还需要让dp[i][a]++和dp[i][-a]++,这相当于设置一个新的起点。


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
    
#define N  1024
#define ll long long
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int MOD   =1000000007;
const double EPS=1e-7;

int dp[N][20010];

int main(){
	int n,a,ans=0;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&a);
		for(int j=0;j<=20000;j++) if(i-1>=0){
			dp[i][j]+=dp[i-1][j-a];
			dp[i][j]+=dp[i-1][j+a];
			dp[i][j]%=MOD;
		}
		ans+=dp[i][10000];
		ans%=MOD;
		dp[i][10000+a]++;
		dp[i][10000-a]++;
	}
	printf("%d\n",ans);
	return 0;
}



抱歉!评论已关闭.