CF #442 div2

A

判断下5个名字出现了几次.pre数据巨弱,就这么一水题在std测刷掉了非常多的人..

/** @Date    : 2017-10-24 16:04:41
  * @FileName: A.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

string a;
map<string, int>q;
string t[5] = { "Danil", "Olya", "Slava", "Ann" , "Nikita"};
int main()
{
	q["Danil"] = 1;
	q["Olya"] = 1;
	q["Slava"] = 1;
	q["Ann"] = 1;
	q["Nikita"] = 1;
	cin >> a;
	int cnt = 0;
	for(int i = 0; i < a.length(); i++)
	{
		for(int j = 0; j < 5; j++)
		{
			string tmp;
			for(int k = 0; k < t[j].length(); k++)
				tmp+=a[i + k];
			//cout << tmp << endl;
			if(tmp == t[j])
			{
				i += t[j].length() - 1, cnt++;
				break;
			}
		}
	}
	printf("%s\n", cnt==1?"YES":"NO");
    return 0;
}

DP思维,记忆化搜索,前后缀什么的都可以.dp[i]['a'/'b']代表到第i个字符时,此时以a结尾和以b结尾的最大长度,也就是a~a和a~b两种串的长度,这样从后往前再扫一遍,合并统计一下取最大值.所以当前为a则必须从a串转移,为b则从a串和ab串中大的转移就好了.这思路还是队友提供的orz 还有种巨短代码的思路其实也比较接近,维护a ab aba的数量不断取大值.

/** @Date    : 2017-10-24 10:43:38
  * @FileName: B.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

char a[5050];
int pre[5050][2];
int suf[5050][2];
int main()
{
	scanf("%s", a + 1);
	int n = strlen(a + 1);
	MMF(pre);
	MMF(suf);
	for(int i = 1; i <= n; i++)
	{
		if(a[i] == 'a')
		{
			pre[i][0] = pre[i - 1][0] + 1;
			pre[i][1] = pre[i - 1][1]; 
		}
		else if(a[i] == 'b')
		{
			pre[i][1] = max(pre[i - 1][0], pre[i - 1][1]) + 1;
			pre[i][0] = pre[i - 1][0];
		}
	}
	for(int i = n; i >= 1; i--)
	{
		if(a[i] == 'a')
		{
			suf[i][0] = suf[i + 1][0] + 1;
			suf[i][1] = suf[i + 1][1];
		}
		else
		{
			suf[i][1] = max(suf[i + 1][0], suf[i + 1][1]) + 1;
			suf[i][0] = suf[i + 1][0];
		}
	}
	int ma = 0;
	for(int i = 0; i <= n; i++)
	{
		int x = max(pre[i][0] + suf[i][1], pre[i][1] + suf[i][0]);
		int y = max(pre[i][0] + suf[i + 1][0], pre[i][1] + suf[i + 1][1]);
		ma = max(ma, max(x, y));
	}
	cout << ma << endl;
    return 0;
}

贪心构造,画一下就知道,炸一个格子会把剩余1次的分到两边去,然后每隔一个格子炸一次,那么就尽可能的把剩余1次的分到了没炸的地方上,同理再进行这样2遍,就能保证炸完所有坦克了,然后注意长度为奇数时,第一遍必定要先炸偶数格,因为这样保证了炸了2遍的格子数比炸一遍的格子数要少1.

/** @Date    : 2017-10-24 10:38:35
  * @FileName: C 构造.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

int ans[5*N];
int main()
{
	int n;
	cin >> n;
	int cnt = 0;
	for(int i = 2; i <= n; i+=2)
		ans[cnt++] = i;
	for(int i = 1; i <= n; i+=2)
		ans[cnt++] = i;
	for(int i = 2; i <= n; i+=2)
		ans[cnt++] = i;
	printf("%d\n", cnt);
	for(int i = 0; i < cnt; i++)
		printf("%d%s", ans[i], i==cnt-1?"\n":" ");
    return 0;
}

D

BFS,4方向一次可走k步询问终点最小消费次数.注意题目说每次只能一个方向最多走k步...那么简单了,但是要注意有个小细节留在了std测,一个格子的一个方向各可以被走一次...不要直接把格子全部标记了..

/** @Date    : 2017-10-24 14:12:19
  * @FileName: D bfs.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

int n, m, k;
int sx, sy, tx, ty;
char mp[1010][1010];
int vis[1010][1010][4];
int dir[4][2]={1,0,-1,0,0,1,0,-1};

int bfs()
{
	queue<pair<pair<int,int> ,int> >q;
	q.push({{sx, sy}, 0});
	MMI(vis[sx][sy]);
	while(!q.empty())
	{
		pair<pair<int,int>, int> nw = q.front();
		q.pop();
		//cout << nw.fi.fi << " " << nw.fi.se << endl;
		if(nw.fi.fi == tx && nw.fi.se == ty)
			return nw.se;
		for(int i = 0; i < 4; i++)
		{
			for(int j = 1; j <= k; j++)
			{
				int x = nw.fi.fi + dir[i][0]*j;
				int y = nw.fi.se + dir[i][1]*j;
				if(x < 1 || x > n || y < 1 || y > m || vis[x][y][i] || mp[x][y] == '#')
					break;
				vis[x][y][i] = 1;
				q.push({{x, y}, nw.se + 1});

			}

		}
	}
	return -1;
}
int main()
{
	scanf("%d%d%d", &n, &m, &k);
	for(int i = 1; i <= n; i++)
		scanf("%s", mp[i] + 1);
	scanf("%d%d%d%d", &sx, &sy, &tx, &ty);
	int ans = bfs();
	printf("%d\n", ans);
    return 0;
}

E

DFS序 线段树,对子树询问1的数量,对子树把1变0,0变1.DFS得到序,用线段树维护和就好了..

/** @Date    : 2017-10-24 11:19:57
  * @FileName: E DFS序 线段树.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 2e5+20;
const double eps = 1e-8;

int pos[N];
int r[N];
int cnt = 0;

struct sion{
	int nxt, to;
}eg[N * 2];
int head[N * 2];
int tot;

int init()
{
	MMF(pos);
	MMF(pos);
	MMF(r);
	MMG(head);
	tot = cnt = 0;
}

void add(int x, int y)
{
	eg[tot].to = y;
	eg[tot].nxt = head[x];
	head[x] = tot++;
}

struct yuu
{
	int l, r;
	int add, sum;
}tt[N << 2];

inline void pushup(int rt)
{
	tt[rt].sum = (tt[rt << 1].sum + tt[rt << 1 | 1].sum);
}

void pushdown(int rt)
{
	if(tt[rt].add != 0)
	{
		tt[rt << 1].add ^= tt[rt].add;
		tt[rt << 1 | 1].add ^= tt[rt].add;
		tt[rt << 1].sum = tt[rt << 1].r - tt[rt << 1].l + 1 - tt[rt << 1].sum;
		tt[rt << 1 | 1].sum = tt[rt << 1 | 1].r - tt[rt << 1 | 1].l + 1 - tt[rt << 1 | 1].sum;

		tt[rt].add ^= 1;
	}
}

void build(int l, int r, int rt)
{
	tt[rt].l = l;
	tt[rt].r = r;
	tt[rt].add = tt[rt].sum = 0;
	if(l == r)
		return ;
	int mid = (l + r) >> 1;
	build(l, mid, rt << 1);
	build(mid + 1, r, rt << 1 | 1);
}

void update(int l, int r, int rt)
{
	if(l <= tt[rt].l && r >= tt[rt].r)
	{
		tt[rt].add ^= 1;
		tt[rt].sum = tt[rt].r - tt[rt].l + 1 - tt[rt].sum;
		return ;
	}
	pushdown(rt);
	int mid = (tt[rt].l + tt[rt].r) >> 1;
	if(l <= mid)
		update(l, r, rt << 1);
	if(r > mid)
		update(l, r, rt << 1 | 1);
	pushup(rt);
}

int query(int l, int r, int rt)
{
	if(l <= tt[rt].l && r >= tt[rt].r)
		return tt[rt].sum;
	pushdown(rt);
	int ans = 0;
	int mid = (tt[rt].l + tt[rt].r) >> 1;
	if(l <= mid)
		ans += query(l, r, rt << 1);
	if(r > mid)
		ans += query(l, r, rt << 1 | 1);
	return ans;
}

int dfs(int x, int pre)
{
	pos[x] = ++cnt;
	for(int i = head[x]; ~i; i = eg[i].nxt)
	{
		if(eg[i].to == pre)
			continue;
		dfs(eg[i].to, x);
	}
	r[x] = cnt;
}


int main()
{
	int n;
	cin >> n;
	init();
	for(int i = 2; i <= n; i++)
	{
		int y;
		scanf("%d", &y);
		add(i, y);
		add(y, i);
	}
	build(1, n, 1);
	dfs(1, -1);
	for(int i = 1; i <= n; i++)
	{
		int v;
		scanf("%d", &v);
		//cout << "~" << v<<endl;
		if(v) update(pos[i], pos[i], 1);
	}
	int q;
	cin >> q;
	char bf[4];
	while(q--)
	{
		int x;
		scanf("%s%d", bf, &x);
		if(bf[0] == 'p')
			update(pos[x], r[x], 1);
		else printf("%d\n", query(pos[x], r[x], 1));
	}
    return 0;
}

F

莫队,离散化,询问区间内的a,b两种书数量之差为k的子区间数量,看到note里的说明和这题意就让人感觉是莫队了,可以先维护下差值的前缀和,然后map存每个前缀和的-k +0 +k这三种值,然后暴力分块转移,但是这里有个问题,普通的1e18数组hash不了,直接用map每次取数暴力转移时logn的复杂度又会超时,而注意到其数目只有1e5*3,那么可以离散化掉3e5个这些数,然后二分预处理出这三种类型的前缀和出现的第一个位置,那么在分块转移的时候,将数量统计在cnt里,利用这个下标进行差分就可以了...

 

/** @Date    : 2017-10-24 18:07:23
  * @FileName: F.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

int n, q;
int f[N];
int blc[N];
LL k;
LL sum[N];
LL cnt[N * 3];
vector<LL>t;
LL p[N][3];
LL res[N];

struct yuu
{
	LL id, l, r;
	bool operator <(const yuu &b) const
	{
		if(blc[l] != blc[b.l])
			return l < b.l;
		return r < b.r;
	}
};
yuu b[N];



int main()
{
	scanf("%lld%lld", &n, &k);
	int sqr = sqrt(1.0 * n);
	for(int i = 1; i <= n; i++)
		scanf("%d", f + i), blc[i] = i / sqr;
	for(int i = 1; i <= n; i++)
	{
		LL x;
		scanf("%lld", &x);
		x *= (f[i]==1?1LL:-1LL);
		sum[i] = sum[i - 1] + x;
		t.PB(sum[i] - k);
		t.PB(sum[i]);
		t.PB(sum[i] + k);
	}
	//别忘了0的差值
	t.PB(-k);//
	t.PB(0);//
	t.PB(k);//
	//
	sort(t.begin(), t.end());
	for(int i = 0; i <= n; i++)
	{
		p[i][0] = lower_bound(t.begin(), t.end(), sum[i] - k) - t.begin();
		p[i][1] = lower_bound(t.begin(), t.end(), sum[i]) - t.begin();
		p[i][2] = lower_bound(t.begin(), t.end(), sum[i] + k) - t.begin();
	}
	/*for(int j = 0; j <= n; j++)
		printf("%2d ", sum[j]);
	cout <<endl;
	for(int i = 0; i < 3; i++, cout<<endl)
		for(int j = 0; j <= n; j++)
			printf("%2d ", p[j][i]);*/
	scanf("%d", &q);
	for(int i = 1; i <= q; i++)
	{
		scanf("%lld%lld", &b[i].l, &b[i].r);
		b[i].id = i;
	}
	sort(b + 1, b + q + 1);
	LL L = 1, R = 0;
	LL ans = 0;
	cnt[p[0][1]] = 1;
	for(int i = 1; i <= q; i++)
	{
		while(L > b[i].l)//
			--L, ans += cnt[p[L - 1][2]], ++cnt[p[L - 1][1]];
		while(L < b[i].l)
			--cnt[p[L - 1][1]], ans -= cnt[p[L - 1][2]], ++L;
		while(R > b[i].r)
			--cnt[p[R][1]], ans -= cnt[p[R][0]], --R;
		while(R < b[i].r)
			++R, ans += cnt[p[R][0]], ++cnt[p[R][1]];
		res[b[i].id] = ans;
	}
	for(int i = 1; i <= q; i++)
		printf("%lld\n", res[i]);
    return 0;
}
posted @ 2017-10-25 21:15  Lweleth  阅读(379)  评论(0编辑  收藏  举报