ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

abc209题解

2021-07-11 13:32:23  阅读:202  来源: 互联网

标签:pre int 题解 abc209 len MAXN include dp


link

A

\(ans=max(0,b-a+1)\)

B

\(\sum a[i]-n/2>=k?\)

C

降智了,一直想容斥,,,浪费了10min。
其实很简单,按 \(a[i]\) 从小到大排序后,由于前面选数一定会使后面能选的数少 \(1\),所以 \(ans=\sum (a[i]-i+1)\)。

D

\(LCA\) 板题,由于两个人走一条边的时间相同,就看他们两个人距离多少边。

E

秒啊,考场时我只想怎么连边,怎么连边都有很多。
其实可以将点看成边,这样边只有 \(n\) 条,点即为前三个字母、后三个字母,点的数量小于等于 \(2n\) 个。再反向建边,发现如果人在此时入度为 \(0\) 的点,必输。发现此时变成了“带环DAG”,于是进行拓扑排序。若有一个必输的点到达 \(x\),那么 \(x\) 一定必赢。反之,看 \(x\) 是否在环上。若在环上,此为平局。若不在,即入度变成了 \(0\),必输。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <iostream>
#define LL long long
using namespace std;
const int MAXN = 4e5 + 5;
int n, len, tot, d[MAXN], vis[MAXN], a[MAXN], b[MAXN];
vector <int> v[MAXN];
string s, s1, s2;
map <string, int> mp;
queue <int> que;
int main() {
	scanf("%d", &n); memset(vis, -1, sizeof(vis));
	for(int i = 1; i <= n; i ++) {
		s.clear(); cin >> s; len = s.length(); s1.clear(); s2.clear();
		s1 += s[0]; s1 += s[1]; s1 += s[2]; s2 += s[len - 3]; s2 += s[len - 2]; s2 += s[len - 1];
//		cout << s1 << ' ' << s2 << endl;
		if(mp.find(s1) == mp.end()) mp[s1] = ++ tot;
		if(mp.find(s2) == mp.end()) mp[s2] = ++ tot;
		a[i] = mp[s1]; b[i] = mp[s2];
		v[b[i]].push_back(a[i]); d[a[i]] ++; 
	}
	for(int i = 1; i <= tot; i ++) if(!d[i]) que.push(i), vis[i] = 0;
	while(!que.empty()) {
		int t = que.front(); que.pop();
		for(int i = 0; i < v[t].size(); i ++) {
			int q = v[t][i]; d[q] --;
			if(vis[q] != 1) {
				if(vis[t] == 0) { vis[q] = 1; que.push(q); continue; }
				if(!d[q]) que.push(q), vis[q] = 0; 	
			}
		}
	}
	for(int i = 1; i <= n; i ++) {
		if(vis[b[i]] == 0) printf("Takahashi\n");
		else if(vis[b[i]] == 1) printf("Aoki\n");
		else printf("Draw\n");
	}
	return 0;
}

F

很容易想到一个贪心:先选最大的。
考虑一段区间 \([L,R](p[L]...p[R])\),不能满足题意当且仅当在区间内存在:\(a[p[i]]<a[p[j]](|p[i]-p[j]|==1,i<j)\)。
换句话说,题目让你求排列的数量,排列满足:对于所有相邻的两个数,大的那个数都比小的那个数先选。看得出来这是一个拓扑图(虽然对正解没什么帮助
考虑 \(dp\),显然这是一个插入 dp。令 \(dp[i][j]\) 为前 \(i\) 个数选了第 \(j\) 个位置的排列数,注意这里的 \(j\) 的前 \(i\) 个数中的相对位置,并不是最终的位置,则隐藏 \(j\leq i\)。
分类讨论。注意边界取不取。
则 \(dp[i][j]=\sum dp[i-1][k]\)。

  1. \(a[i-1]<a[i]\),\(j \leq k \leq i - 1\),这里 \(k==j\) 时相当于 \(a[i-1]\) 原来在 \(j\) 处,插入 \(a[i]\) 在 \(a[i-1]\) 前,它也在 \(j\) 处,于是可行。
  2. \(a[i-1]>a[i]\),\(1 \leq k \leq j-1\)。
  3. \(a[i-1]==a[i]\),\(1 \leq k \leq i-1\)。
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define LL long long
using namespace std;
const int MAXN = 4005, Mod = 1e9 + 7;
int n, a[MAXN], ans;
LL dp[MAXN][MAXN], pre[MAXN];
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
	dp[1][1] = 1; pre[1] = 1;
	for(int i = 2; i <= n; i ++) {
		for(int j = 1; j <= i; j ++) {
			if(a[i] > a[i - 1]) dp[i][j] = pre[i - 1] - pre[j - 1];
			else if(a[i] < a[i - 1]) dp[i][j] = pre[j - 1];
			else dp[i][j] = pre[i - 1];
			dp[i][j] = (dp[i][j] % Mod + Mod) % Mod;
		}
		for(int j = 1; j <= i; j ++) pre[j] = (pre[j - 1] + dp[i][j]) % Mod;
	}
	for(int i = 1; i <= n; i ++) ans = (ans + dp[n][i]) % Mod;
	printf("%d", ans);
	return 0;
}

标签:pre,int,题解,abc209,len,MAXN,include,dp
来源: https://www.cnblogs.com/Kidulthood/p/14998429.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有