训练赛Day6-The 36th ACM/ICPC Asia Regional Beijing Site

B - Eliminate Witches!

题目大意

【样例解释】

给你一个字符串:

walpurgis(charlotte(patricia,gertrud),elly,gisela) 

如下图:

现在要你输出该树节点个数以及先序遍历,和遍历中的访问边的顺序。例如该样例输出如下:

6
walpurgis
charlotte
patricia
gertrud
elly
gisela
1 2
2 3
3 2
2 4
4 2
2 1
1 5
5 1
1 6
6 1 

数据范围

多组输入T <= 20,每个字符串不超过50000个节点,且每个节点对应的字符串长度不超过10,所有输入字符串长度不超过1000000。

解题思路

暴力模拟,首先可以看出该树的先序遍历就是字符串的先后出现顺序,并且还可以发现树的节点个数就是字符串中’(‘的个数加’,’的个数在加一,也就是节点个数 = cnt[‘(‘] + cnt[‘,’] + 1。之后再暴力Dfs模拟先序遍历顺序以及回溯过程即可。

AC代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
const int maxn = 1000000;
int T, len, l, now, tot;
char s[maxn + 5];
char c[15];
vector<pair<int, int> >ans;
void solve() {int tot = -1;for(int i = 0; i < len; i++){if(s[i] >= 'a' && s[i] <= 'z')c[++tot] = s[i] ;else if(s[i] == ',') {if(tot >= 0) {c[++tot] = '\0';printf("%s\n", c);tot = -1;}}else if(s[i] == '(') { c[++tot] = '\0';printf("%s\n", c);tot = -1;}else if(s[i] == ')') {if(tot >= 0) {c[++tot] = '\0';printf("%s\n", c);tot = -1;}}}if(tot >= 0) {c[++tot] = '\0';printf("%s\n", c);}
}
void Dfs(int fa) {while(l < len) {if(s[l] >= 'a' && s[l] <= 'z')++tot, l++;else if(s[l] == ',') {if(tot >= 0) {tot = -1;now++;ans.push_back(make_pair(fa, now));ans.push_back(make_pair(now, fa));}l++;}else if(s[l] == '(') { tot = -1;now++;if(fa != 0)ans.push_back(make_pair(fa, now));l++;int tmp = now;Dfs(now);if(fa != 0)ans.push_back(make_pair(tmp, fa)); }else if(s[l] == ')') {if(tot >= 0) {now++;ans.push_back(make_pair(fa, now));ans.push_back(make_pair(now, fa));tot = -1;}l++;return ;}}}
int main() {scanf("%d", &T);while(T--) {ans.clear(); now = 0, l = 0, tot = -1;scanf("%s", s);len = strlen(s);int p = 0, i = 0;while(i < len) {if(s[i] == '(' || s[i] == ',')p++;i++;}printf("%d\n", p + 1);solve();Dfs(0);for(int i = 0; i < ans.size(); i++)printf("%d %d\n", ans[i].first, ans[i].second);printf("\n");}return 0;
}

D - FXTZ II

题目大意

A,B两个人在玩一个游戏,即有n个球,球的标号是从1~n的,并且每个球有一个攻击力,攻击力的大小个球的标号有关,标号为i的球的攻击力等于2i−12i−12^{i - 1}。现在游戏规则是这样的,A每次随机出一个球,并且每个球只能被随机到一次,且这个球会有50%的概率攻击A,同样也有50%的概率攻击B。A,B初始血量都是2n2n2^n。每一轮过后,如果A的血量低于B的血量那么A就输了,否则当所有球都用完之后A还没有输的话,那么A就赢了,现在问你A赢的概率。要求以分数最简式的形式输出答案。

数据范围

多组输入T<=30,球的个数n<=500。

解题思路

首先我们可以知道2i−1=20+21+⋯+2i−12i−1=20+21+⋯+2i−12^i -1= 2^0+2^1+\dots+2^{i-1}。所以,假如B得了一个标号最大的球,那么不管之后怎么取A一定是赢的,而当B得了一个i号球,且i不等于n,那么之后A要赢的话之后一轮取到比i大的球都必须给B,也就是B取到球的标号是递增的,而我们可以知道n个球一共有n!n!n!种取球的顺序,那么我们对于每一个排列顺序都可以知道A赢的概率,求出所有的排列的概率在求和即可求出A赢的概率。但是n有500那么大,如果照这个方法暴力显然不能写,但是通过打表打得n从1~10的几项发现,在未最简化的情况下,每一项的分母都是n!∗2nn!∗2nn!*2^n,而分子则呈现第i项的分子是第i-1项分子的2 * i - 1倍。看到分母应该就得想到显然得大整数写了,Java的大整数就行。

AC代码

import java.util.*;
import java.math.*;public class Main {static BigInteger zo = new BigInteger("0");public static BigInteger Gcd(BigInteger x, BigInteger y) {if(x.remainder(y).compareTo(zo) == 0) return y;return Gcd(y, x.remainder(y));}public static void main(String []args) {Scanner cin = new Scanner(System.in);BigInteger [] fac = new BigInteger[505];BigInteger [] f = new BigInteger[505];BigInteger [] Pow = new BigInteger[505];fac[0] =new BigInteger("1");f[0] = new BigInteger("1");Pow[0] = new BigInteger("1");for (int i = 1; i <= 500; i++) {BigInteger val = BigInteger.valueOf(i);fac[i] = fac[i - 1].multiply(val);BigInteger v = BigInteger.valueOf(2 * i - 1);f[i] = f[i - 1].multiply(v);BigInteger w = new BigInteger("2");Pow[i] = Pow[i - 1].multiply(w);}int T = cin.nextInt();for (int cas = 1; cas <= T; cas++) {int n = cin.nextInt();BigInteger gcd = Gcd(f[n], fac[n].multiply(Pow[n]));System.out.println(f[n].divide(gcd).toString() + "/" + fac[n].multiply(Pow[n]).divide(gcd).toString());}}
}

懒得写了,放了队友代码。。。。


F - Machine scheduling

题目大意

n个数取r个分成小于等于m组的方案数,并且取出的r个数要求两两之间的差值必须大于等于k。

数据范围

1≤n,r,k,m≤10001≤n,r,k,m≤10001\leq n,r,k,m \leq 1000,要求答案模109+7109+710^9+7。

解题思路

首先将此题分成两部分分开求解,第一部分是n个数取r个满足要求的有多少个,第二部分是r个数分成m的方案数。因为两个问题相互独立,所以最后答案就是第一部分的方案数乘上第二部分的方案数。

首先看第二部分,是一个斯特林数,也可以看做是一个DP问题,S[i][j]代表前i个数分成j组的方案数,那么S[i][j]可以由S[i-1][j-1]转移过来,因为可以将第i个数单独作为第j组;S[i][j]也可以由S[i-1][j]转移过来,第i个数可以放在j组中的任意一组,所以总转移状态为S[i][j]=S[i−1][j−1]+S[i−1][j]∗jS[i][j]=S[i−1][j−1]+S[i−1][j]∗jS[i][j]=S[i-1][j-1]+S[i-1][j]*j。所以第二部分总的方案数就是∑mj=0S[n][j]∑j=0mS[n][j]\sum _{j = 0}^mS[n][j]。

然后看第一部分,n个数取r个即有d=n−((r−1)∗k+1)d=n−((r−1)∗k+1)d=n-((r-1)*k+1)个空闲的数,因为这样保证了满足任意两个数差值大于等于k的条件,然后可以看做成r+d个数取r个数的方案个数。

最后两部分相乘取模即可。

AC代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn = 1010;
const int Pt = 1e9 + 7;
int n, r, k, m;
LL c[maxn + 5][maxn + 5];
LL S[maxn + 5][maxn + 5];
void Init() {for(int i = 0; i <= maxn; i++)c[i][0] = 1;for(int i = 1; i <= maxn; i++)for(int j = 1; j <= i; j++)c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % Pt;for(int i = 0; i <= maxn; i++)S[i][0] = 0LL, S[i][i] = 1LL; S[0][0] = 1LL;for(int i = 1; i <= maxn; i++)for(int j = 1; j <= i; j++)S[i][j] = (S[i - 1][j - 1] + S[i - 1][j] * j % Pt) % Pt;
}
int main() {Init();while(scanf("%d%d%d%d", &n, &r, &k, &m) != EOF) {int d = n - ((r - 1) * k + 1);if(d < 0)printf("0\n");else {d += r; LL res = 0LL;for(int i = 0; i <= m; i++) res = (res + c[d][r] * S[r][i] % Pt) % Pt;printf("%lld\n", res);}}return 0;
}

G - Panda

题目大意

给你一个长度为n的且只包含字符’b’和’w’的字符串,然后m个操作,操作0代表查询区间[l,r]字符串”wbw”的个数(可以重叠),操作1代表修改第k个字符为ch。

数据范围

多组输入T<=100,n<=50000,m<=10000。

解题思路

可以发现每做一次修改只会影响到3个位置的值,因为查询较多,可以用树状数组维护前i个字符有多少个”wbw”串,并记下以第i个结尾是否有”wbw”,那么修改k位置的话,只需要先将k,k+1,k+2位置的答案先减掉,之直接修改字符串并判断k,k+1,k+2位置有无”wbw”串,有则更新答案。

AC代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 50000;
char s[maxn + 5];
int c[maxn + 5];
int vis[maxn + 5];
int n, m;
int lowbit(int x) {return x & -x;
}
void add(int x, int y) {while(x <= maxn) {c[x] += y;x += lowbit(x);}
}
int sum(int x) {int res = 0;while(x > 0) {res += c[x];x -= lowbit(x);}return res;
}
int main() {int T, cas = 0; scanf("%d", &T);while(T--) {memset(vis, 0, sizeof(vis));memset(c, 0, sizeof(c));scanf("%d%d", &n, &m);scanf("%s", s + 1);for(int i = 1; i <= n - 2; i++) {if(s[i] == 'w' && s[i + 1] == 'b' && s[i + 2] == 'w') {vis[i + 2] = 1;add(i + 2, 1);}}printf("Case %d:\n", ++cas);while(m--) {int op;scanf("%d", &op);if(op == 0) {int l, r;scanf("%d%d", &l, &r); l++, r++;printf("%d\n", max(0, sum(r) - sum(l + 1)));}else {int l; char ch;scanf("%d %c", &l, &ch); l++;s[l] = ch;for(int i = l; i <= min(l + 2, n); i++) {add(i, -vis[i]);vis[i] = 0;}for(int i = max(1, l - 2); i <= l; i++) {if(s[i] == 'w' && s[i + 1] == 'b' && s[i + 2] == 'w') {add(i + 2, 1);vis[i + 2] = 1;}}}}}
}

J-Tourism Planning

题目大意

有n个人,m个景点,每个景点都需要门票,每去一个景点就需要花费对应的兴趣值,然后每个人去景点也会获得对应的兴趣值,并且特别的如果多个人在一个景点将会获得额外的兴趣值。现在要你求最大兴趣值和。如果不大于0则输出”STAY HOME”。

数据范围

1≤N≤10,1≤M≤101≤N≤10,1≤M≤101\leq N\leq 10,1\leq M\leq 10,分别代表N个人和M个景点,1≤Pi≤10001≤Pi≤10001\leq P_i\leq1000,代表一个人去第i个地方需要花费的兴趣值,1≤i≤N,1≤j≤M,1≤Vij≤1000,1≤i≤N,1≤j≤M,1≤Vij≤1000,1\leq i\leq N,1\leq j\leq M,1\leq V_{ij}\leq 1000,代表第i个人去第j个景点获得的兴趣值,1≤i≤N,1≤j≤N,1≤Bij≤1000,1≤i≤N,1≤j≤N,1≤Bij≤1000,1\leq i\leq N,1\leq j\leq N,1\leq B_{ij}\leq 1000,代表i,j两个人在同一景点会产生的兴趣值。

解题思路

dp[i][s]dp[i][s]dp[i][s]代表前i个景点在访问为s的状态下的最大兴趣值。那么它可以由第i-1的景点的状态转移过来,但是因为人数是不递增的,那么dp[i][s]=max(dp[i−1][j]+c[i][s]),dp[i][s]=max(dp[i−1][j]+c[i][s]),dp[i][s] = max(dp[i-1][j]+c[i][s]),其中s≤j≤(1<<n)−1,s≤j≤(1<<n)−1,s\leq j\leq (1 c[i][s]c[i][s]c[i][s]代表第i个景点在s状态下的兴趣值,而c[i][s]c[i][s]c[i][s]的话,对每个状态找出哪些人访问了该景点,以及多个人之间的额外兴趣值。

具体见代码:

AC代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
const int INF = 1000000;
const int maxn = 2000;
int dp[15][maxn + 5], c[15][maxn + 5];
int p[15], v[15][15], b[15][15];
int n, m;
void Init() {for(int i = 1; i <= m; i++) {for(int s = 0; s < (1 << n); s++) {c[i][s] = 0;for(int j = 1; j <= n; j++) {if((1 << (j - 1)) & s) {c[i][s] += (v[j][i] - p[i]);for(int k = 1; k < j; k++) {if((1 << (k - 1) & s))c[i][s] += b[j][k];}}}}}
}
void solve() {int Max = -INF;for(int i = 1; i <= m; i++)for(int s = 0; s < (1 << n); s++)dp[i][s] = -INF;for(int i = 1; i <= m; i++) {for(int s = 0; s < (1 << n); s++) {for(int j = s; j < (1 << n); j++) {if((s & j) == s) {dp[i][s] = max(dp[i][s], dp[i - 1][j] + c[i][s]);}}if(i == m)Max = max(Max, dp[m][s]);}}if(Max <= 0)printf("STAY HOME\n");else printf("%d\n", Max);
}
int main() {while(~scanf("%d%d", &n, &m)) {if(n == 0 && m == 0)break;for(int i = 1; i <= m; i++)scanf("%d", &p[i]);for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)scanf("%d", &v[i][j]);for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)scanf("%d", &b[i][j]);Init();solve();}return 0;
}

训练赛Day6-The 36th ACMICPC Asia Regional Beijing Site相关推荐

  1. 2014 ACM/ICPC Asia Regional Beijing Site

    1001 A Curious Matt 1002 Black And White 1003 Collision 1004 Dire Wolf 1005 Everlasting L 1006 Fluor ...

  2. The 36th ACM/ICPC Asia Regional Dalian Site 1006 Dave

    Dave Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65768/65768K (Java/Other) Total Submissi ...

  3. JAG Practice Contest for ACM-ICPC Asia Regional 2016.K.Non-redundant Drive(点分治)

    Atcoder vjudge 这标题好长... \(Description\) 给定一棵\(n\)个点的树.在每个点\(i\)你可以补充\(g_i\)的油量,经过一条边需要花费边长的油量.你可以选择从 ...

  4. HDU 4069 Squiggly Sudoku(DLX)(The 36th ACM/ICPC Asia Regional Fuzhou Site —— Online Contest)...

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4069 Problem Description Today we play a squiggly sud ...

  5. The 37th ACM/ICPC Asia Regional HangZhou Site Online Contest - F

    本题通过率相当低....原因是绝大多数队都是直接贪心吧...找出A最小且B不为0的怪作为入口..可以将所有的B不为0的怪连起来...而中间的间隔可以把 B为0的怪干掉....最后再一一消灭 B 为0的 ...

  6. Problem 1002-2017 ACM/ICPC Asia Regional Shenyang Online

    网络赛:2017 ACM/ICPC Asia Regional Shenyang Online 题目来源:cable cable cable Problem Description: Connecti ...

  7. 2018-2019 ACM-ICPC, Asia Shenyang Regional Contest 不完整题解与训练赛复盘

    RT,训练赛复盘+题解,赛中过6题,又比理论上界少1题( 发挥比较惊险刺激,前期直接拉闸,中后期翻盘成功. (别问我为什么又紫了,这波是两场div1各掉快100分,第二场试图跳车,不知道跳下去没有) ...

  8. The 2014 ACM-ICPC Asia Mudanjiang Regional Contest(2014牡丹江区域赛)

    The 2014 ACM-ICPC Asia Mudanjiang Regional Contest 题目链接 没去现场.做的网络同步赛.感觉还能够,搞了6题 A:这是签到题,对于A堆除掉.假设没剩余 ...

  9. 2018-2019 ACM-ICPC, Asia Nanjing Regional Contest题解

    以下所有AC题解程序来自"仙客传奇"团队. AC题数:6/13 ADGIJK A. Adrien and Austin AC的C++语言程序: #include <iostr ...

最新文章

  1. python一点基础都没有的怎么办-Python基础知识细节点总结,零基础一分钟也能掌握...
  2. VelocityTracker简单介绍
  3. 微软确定 Win10 付费才能玩 还能不能愉快玩耍?
  4. AIM Tech Round 3 (Div. 2) A B C D
  5. [蓝桥杯2018初赛]星期一-日期计算
  6. view如何接受json_如何将你的 ThinkJS 项目部署到 ZEIT 上
  7. SQL SERVER 参考:游标(Cursor)的讲解与实例
  8. LeetCode 548. 将数组分割成和相等的子数组(哈希set)
  9. 转发-[原创]ASR1K 在Rommon导入IOS-XE启动
  10. iOS开发:AVPlayer实现流音频边播边存
  11. [转载] C++ std::vector指定位置插入
  12. 开课吧:数据分析师常用的分析方法有哪些?
  13. 搭建docker监控平台
  14. 老徐小程序之小程序怎么选?
  15. 系统检测到您疑似使用网页抓取工具访问本_12款最常使用的网络爬虫工具推荐...
  16. 有必要说一说即将到来的春招(经历+重要性+如何准备)
  17. 自适应滤波:递归最小二乘
  18. Ubuntu20中使用AirSim--亲测可用
  19. php计算三角形的面积,PHP实现的简单三角形、矩形周长面积计算器分享
  20. Ecmall 的增删改操作

热门文章

  1. 【靶场平台】一些免费好用的靶机渗透测试环境
  2. 如何用PS把夏天变成冬天
  3. STM32基于IIC通信协议的OLED模块使用(详解)
  4. C#泛型集合定义及使用
  5. Microsoft Visual Studio 2022 项目打包详细步骤(初学者必会)
  6. 百度城市大脑业务架构和总体架构
  7. 【CV-project】看图说话(Image Captioning)
  8. 我用C++的理由——关于C和C++的选择
  9. portlet是什么?
  10. 2013年计算机考研试题,2009-2013年计算机组成考研原试题与答案