2012长春网络赛

acmicpc 解题报告汇总:http://acmicpc.info/archives/823


1:

线段树

(i-a)%k = 0 即i%k=a%k

节点维护一个二维数组add, add[a][b]=c,表示该区间下标i%a=b的加c

那么,  update(l, r, k, l%k, v)这样就可以分到子区间了

但是, 这样会爆内存,因为a%b<b,可以节省一半, 这样就过了..

#pragma warning (disable: 4786)
#include "stdio.h"
#include "string.h"
#include "iostream"
#include "algorithm"
#include "vector"
#include "map"
#include "set"

using namespace std;

const int N = 50005;

int seg[N*3][55], da[N];

void update(int l, int r, int a, int b, int c, int rt, int L, int R) {
	if(l <= L && R <= r) {
		int i, ii = b;
		for(i = 1; i < a; ++i) {
			ii += i;
		}
		seg[rt][ii] += c;
		return;
	}
	int mid = (L+R)>>1;
	if(l <= mid) {
		update(l, r, a, b, c, rt<<1, L, mid);
	}
	if(r > mid) {
		update(l, r, a, b, c, rt<<1|1, mid+1, R);
	}
}

int query(int x, int rt, int L, int R) {
	int mid = (L+R)>>1, res = 0, i, j, ii;
	
	for(i = 1; i <= 10; ++i)
	{
		ii = x%i;
		for(j = 1; j < i; ++j) {
			ii += j;
		}
		res += seg[rt][ii];
	}

	if(x <= L && R <= x) {
		return res;
	}

	if(x <= mid) {
		res += query(x, rt<<1, L, mid);
	}
	if(x > mid) {
		res += query(x, rt<<1|1, mid+1, R);
	}

	return res;
}

int main()
{
	int n, q, i;

	while(~scanf("%d", &n))
	{
		for(i = 1; i <= n; ++i) {
			scanf("%d", &da[i]);
		}
		memset(seg, 0, sizeof(seg));
		scanf("%d", &q);
		int t, l, r, k, v;
		while(q--) {
			scanf("%d", &t);
			if(t==1) {
				scanf("%d%d%d%d", &l, &r, &k, &v);
				update(l, r, k, l%k, v, 1, 1, n);
			}
			else if(t==2) {
				scanf("%d", &i);
				printf("%d\n", da[i]+query(i, 1, 1, n));
			}
		}
	}

	return 0;
}



2:

先按第一维排序,然后第二维
然后对a的每个i,找出小于a[i].h的b.h,将对应的w塞到集合里
刚才已经保证了第一维满足了
然后贪心的从集合里面找a[i]能覆盖的最大的w

#pragma warning (disable: 4786)
#include "stdio.h"
#include "string.h"
#include "iostream"
#include "algorithm"
#include "vector"
#include "map"
#include "set"

using namespace std;

typedef pair<int,int> PII;

vector<PII> a, b;
multiset<int> c;
multiset<int>::iterator it;

int main()
{
    int t, n, h, w, i, j;

    scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        a.clear();
        b.clear();
        for(i = 0; i < n; ++i) {
            scanf("%d%d", &h, &w);
            a.push_back(make_pair(h, w));
        }
        for(i = 0; i < n; ++i) {
            scanf("%d%d", &h, &w);
            b.push_back(make_pair(h, w));
        }

        sort(a.begin(), a.end());
        sort(b.begin(), b.end());

        int ans = 0;
        c.clear();
        for(i=j=0; i<a.size(); ++i) {
            while(j<b.size() && b[j].first<=a[i].first) {
                c.insert(b[j].second);
                ++j;
            }
            it = c.upper_bound(a[i].second);
            if(it != c.begin() && !c.empty()) {
                --it;
                c.erase(it);
                ++ans;
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}


8:

dfs求出每个点的取值范围, 如果出现up<down的, 则矛盾...

#pragma warning (disable: 4786)
#include "cstdio"
#include "cstring"
#include "cassert"
#include "iostream"
#include "algorithm"
#include "vector"
#include "map"
#include "set"

using namespace std;

typedef __int64 ll;
typedef pair<ll, ll> PII;
typedef vector<int> VI;

#define max(a, b) a>b?a:b
#define min(a, b) a<b?a:b

const int N = 11111;
const ll inf = 0x7fffffffffffffff;

VI mat[N];
PII seg[N];

int ok;

void calc(int i, ll d, ll u) {
	ll nd = max(d, seg[i].first),
		nu = min(u, seg[i].second);
	if(nu < nd) {
		ok = 0;
	}
	seg[i].first = nd;
	seg[i].second = nu;
}

void dfs(int rt) {
	if(!ok || mat[rt].size() == 0) { return; }

	int i;
	ll dw = 1, up = inf;
	for(i = 0; i < mat[rt].size(); ++i) {
		dfs(mat[rt][i]);
		dw += seg[mat[rt][i]].first;
	}
	calc(rt, dw, up);
}

int main()
{
	char c;
	int n, m, f, a, b, i;
	ll dw, up;

	while(~scanf("%d", &n)) {
		for(i = 1; i <= n; ++i) {
			seg[i].first = 1;
			seg[i].second = inf;
			mat[i].clear();
		}

		for(i = 2; i <= n; ++i) {
			scanf("%d", &f);
			mat[f].push_back(i);
		}

		ok = 1;
		scanf("%d", &m);
		while(m--) {
			scanf("%d %c %d", &a, &c, &b);
			dw = 1;
			up = inf;

			if(c=='=') { dw = up = b; }
			else if(c=='<') { up = b-1; }
			else if(c=='>') { dw = b+1; }
			else { assert(0>1); }

			calc(a, dw, up);
		}
		dfs(1);
		puts(ok?"True":"Lie");
	}
	return 0;
}





11:

暴力, 3^15,

敲代码的时候两个set轮换...

卡过去了...

#pragma warning (disable: 4786)
#include "stdio.h"
#include "string.h"
#include "iostream"
#include "algorithm"
#include "vector"
#include "map"
#include "set"

using namespace std;

struct node{
	int a, b, c;
	node() { a=b=c=0; }
	node(int aa, int bb, int cc):a(aa), b(bb), c(cc){}

	bool operator < (const node & tmp) const
	{
		if(a!=tmp.a) { return a<tmp.a; }
		else if(b!=tmp.b) { return b<tmp.b; }
		else { return c<tmp.c; }
	}

	bool operator == (const node & tmp) const
	{
		return (a==tmp.a && b==tmp.b && c==tmp.c);
	}
	node operator + (const node & tmp) const
	{
		int aa=a+tmp.a, bb=b+tmp.b, cc=c+tmp.c;
		if(aa>bb) { swap(aa, bb); }
		if(aa>cc) { swap(aa, cc); }
		if(bb>cc) { swap(bb, cc); }

		return node(aa, bb, cc);
	}
};

int isok(const node& n) {
	return (n.a+n.b>n.c);
}

vector<int> v;
set<node> s[2];

int main()
{
	int t, n, x, i;

	scanf("%d", &t);
	while(t--) {
		scanf("%d", &n);
		v.clear();
		for(i=0; i<n; ++i) {
			scanf("%d", &x);
			v.push_back(x);
		}

		s[0].clear();
		s[0].insert(node());

		int a=0, b=1;
		set<node>::iterator it;
		for(i=0; i<n; ++i)
		{
			s[b].clear();
			for(it=s[a].begin(); it!=s[a].end(); ++it) {
				s[b].insert(*it+node(v[i], 0, 0));
				s[b].insert(*it+node(0, v[i], 0));
				s[b].insert(*it+node(0, 0, v[i]));
			}

			swap(a, b);
		}

		int ans = 0;
		for(it=s[a].begin(); it!=s[a].end(); ++it) {
			if(isok(*it)) { ++ans; }
		}

		printf("%d\n", ans);
	}

	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值