【2018暑假集训模拟一】Day2题解
T1 园艺工人的求助
【题目描述】
终于,在一段繁忙的训练之后,到了NOIP 的举办的时候。同学们坐上了大巴车,享受着沿途的风光,讨论着未解决的问题,憧憬着NOIP 赛场上切题的样子。很快,大
巴车到了大连大学科技楼,也就是辽宁NOIP 的举办地点。大连大学科技楼是一幢宏伟的建筑,楼前摆放有一排花,共有n 盆。花一共只有26 种,分别用26 个小写英文
字母表示,也就是说,楼前的这排花可以用一个仅包含小写英文字母的字符串表示。大连大学雇了一个园艺工人,专门打理科技楼前的花。园艺工人看见你,热情地向你打招呼:“NOIP 加油!”其实,他是有问题想请你帮忙呢!现在园艺工人想再购买一盆花(可以任选26 种花中的一种),插入到原来的花中间(可以放在整排花的最左侧与最右侧),他想知道在插入一盆花后,能否使整排花左右对称。例如,ababa 是左右对称的,而abcd 不是。注意:即使原来的一排花已经是左右对称的,也必须再插入一盆花。
【输入格式】
从文件flower.in 中读入数据。
本题目有多组数据,输入第一行为一个正整数t,表示数据组数。
接下来t 行,每行包含一个正整数n 和一个长度为n 的字符串,分别表示花的数量与花构成的序列。
【输出格式】
输出到文件flower.out 中。
对于每组数据输出一行。若再插入一盆花之后能使整排花左右对称,输出Yes,否则输出No(注意大小写)。
【样例1 输入】
4
4 abcd
4 aabb
4 aaaa
10 abcdefecba
【样例1 输出】
No
No
Yes
Yes
【子任务】
对于20% 的数据,n <= 5;
对于另30% 的数据,t = 1 且n <= 1000;
对于100% 的数据,Σn <= 106。
题面好像就最后两句话有用。
就是说给一个字符串,再插入一个字符后能否成为一个回文串。
首先,如果他是回文串,那么插入一个字符后一定还是回文串,这个想想就明白了。
如果不是回文串,因为Σn <= 10 6,所以对于每一个字符串,我们暴力的从头L和尾R两个端点开始一个一个比对就行。然后遇到一个不一样的字符,我们需要考虑是往L那一端插入字符还是往R端插,分情况讨论即可,然后如果两种方案都又遇到不相等的字符,就输出No了,而其中一种方案成立,就Yes。
代码实现时,插入字符可以理解为这一端的指针向前跳一个字符。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter printf("\n") 13 #define space printf(" ") 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const ll INF = 0x3f3f3f3f; 18 const int eps = 1e-8; 19 const int maxn = 4e5 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ' '; 24 while(!isdigit(ch)) {last = ch; ch = getchar();} 25 while(isdigit(ch)) 26 { 27 ans = ans * 10 + ch - '0'; ch = getchar(); 28 } 29 if(last == '-') ans = -ans; 30 return ans; 31 } 32 inline void write(ll x) 33 { 34 if(x < 0) x = -x, putchar('-'); 35 if(x >= 10) write(x / 10); 36 putchar(x % 10 + '0'); 37 } 38 39 int n, m, s, t; 40 struct Node 41 { 42 int x, y; ll c; 43 }a[maxn]; 44 45 vector<ll> v[maxn], c[maxn], v2[maxn], c2[maxn]; 46 47 ll dis[2][maxn]; 48 ll num[2][maxn]; 49 bool vis[maxn]; 50 struct Dij //用pair看起来更简洁 51 { 52 int num; ll cost; 53 bool operator < (const Dij& other)const 54 { 55 return cost > other.cost || (cost == other.cost && num > other.num); 56 } 57 }; 58 void dijkstra(int x, int p) 59 { 60 for(int i = 1; i <= n; ++i) disView Code [p][i] = INF * INF; 61 Mem(vis); 62 priority_queue<Dij> q; 63 q.push((Dij){x, 0}); 64 dis[p][x] = 0; num[p][x] = 1; 65 while(!q.empty()) 66 { 67 Dij node = q.top(); q.pop(); 68 int now = node.num; 69 if(vis[now]) continue; 70 vis[now] = 1; 71 for(int i = 0; i < (int)v[now].size(); ++i) 72 { 73 if(dis[p][now] + c[now][i] < dis[p][v[now][i]]) 74 { 75 dis[p][v[now][i]] = dis[p][now] + c[now][i]; 76 num[p][v[now][i]] = num[p][now]; 77 q.push((Dij){v[now][i], dis[p][v[now][i]]}); 78 } 79 else if(dis[p][now] + c[now][i] == dis[p][v[now][i]]) num[p][v[now][i]] += num[p][now]; 80 } 81 } 82 } 83 84 ll ans[maxn]; 85 86 int main() 87 { 88 freopen("road.in", "r", stdin); 89 freopen("road.out", "w", stdout); 90 n = read(); m = read(); s = read(); t = read(); 91 for(int i = 1; i <= m; ++i) 92 { 93 a[i].x = read(); a[i].y = read(); a[i].c = read(); 94 v[a[i].x].push_back(a[i].y); 95 c[a[i].x].push_back(a[i].c); 96 } 97 dijkstra(s, 0); 98 for(int i = 1; i <= n; ++i) {v[i].clear(); c[i].clear();} 99 for(int i = 1; i <= m; ++i) 100 { 101 v[a[i].y].push_back(a[i].x); 102 c[a[i].y].push_back(a[i].c); 103 } 104 dijkstra(t, 1); 105 for(int i = 1; i <= m; ++i) 106 { 107 if(dis[0][a[i].x] + dis[1][a[i].y] + a[i].c > dis[0][t]) 108 { 109 ll dx = dis[0][a[i].x] + dis[1][a[i].y] + a[i].c - dis[0][t] + 1; 110 if(a[i].c - dx > 0) ans[i] = dx; //别忘了减完后边权还得是正的 111 } 112 else 113 { 114 if(num[0][a[i].x] * num[1][a[i].y] == num[0][t]) ans[i] = -1; 115 else if(a[i].c > 1) ans[i] = 1; //减1后边权要大于0 116 } 117 } 118 for(int i = 1; i <= m; ++i) 119 { 120 if(ans[i] == -1) printf("YES\n"); 121 else if(!ans[i]) printf("NO\n"); 122 else printf("CAN %lld\n", ans[i]); 123 } 124 return 0; 125 }
T3 归程的谜题
【题目描述】
NOIP 结束了,你踏上了归程。在大巴车上,你很无聊,于是你想了一个谜题来娱
乐一下。
若一个二维数组每个元素都是(或) 中的一个,那么这个数组被成为括号二维
数组。从二维数组的左上角(1; 1) 出发,每次向右或向下移动一格,直到走到右下角
(n;m),这样的路径被成为单调路径。自然地,一条单调路径上的所有字符按顺序相连
可以构成一个括号串。
如果一个括号二位数组的每一条单调路径所对应的括号串都是匹配的括号串,那
么这个括号二维数组被称为匹配的括号二维数组。
现在定义两个相同大小的匹配的括号二维数组的一个比较函数(比较数组a 和b)。
假设二维数组中每个元素都有一个优先级。优先级为1 到nm 的整数,且两两不同(设
优先级储存在一个和a; b 同样大小的二维数组c 中)。然后找到所有ai; j , bi; j 的位置。
如果有多个这样的位置,就选择ci; j 最小的位置。如果ai; j =(,则a < b,否则a > b;
若没有这样的位置,则a = b。
有了比较函数,我们可以给一定大小所有匹配的括号二维数组从小到大排序,你希
望找出具有指定大小的第k 个匹配的括号二维数组。
数据保证第k 个匹配的括号二维数组存在。
【输入格式】
从文件puzzle.in 中读入数据。
第一行有三个正整数n;m; k (1 n;m 500; 1 k 1018),分别表示二维数组的行
数、列数、你希望找到的匹配的括号二维数组的序数。
接下来n 行,每行m 个正整数,表示优先级数组(优先级两两不同)。
【输出格式】
输出到文件puzzle.out 中。
输出n 行,每行一个长度为m 的字符串,表示所求得的二维数组。
【样例1 输入】
3 2 2
3 6
1 4
2 5
第6 页共7 页
全国青少年信息学奥林匹克联赛NOIP 第二试归程的谜题(puzzle)
【样例1 输出】
()
)(
()
【样例2】
见选手目录下的puzzle/puzzle2.in 与puzzle/puzzle2.ans。
【子任务】
对于20% 的数据,n;m 10;
对于另20% 的数据,k 10;
对于另20% 的数据,n = 1。
就是CF123C。
题面我刚开始是没懂,考试剩后一个小时的时候我又读了一遍,总算明白了。还是那句话,多读几遍救懂了……
首先得发现这么个性质,看看下面这个图
这两条路线除了经过1和2号格子不同外,其他格子都相同,而又因为这两条路线都是合法的括号序列,所以可以推出,格子1和2的括号是相同的。那么进一步得出结论,每一个对角线上的括号都是相同的,换句话说只要确定了其中一条路径,那么整张图就确定了。
现在问题转化成了求一条第k小的长度为(n +m - 1)的合法括号序列。
首先我们将所有优先级映射到任意一条序列上,并保证序列第 i 位置的优先级是该格子所在对角线上最小的。接着顺着优先级尝试填这个格子括号,然后计算出在一些位置已经确定的括号
- 【2018暑假集训模拟一】Day1题解
- 2018暑假辽宁省集训划水记
- 暑假集训7.29 一般表达式转换后缀表达式(手写模拟栈....)sdutoj2132
- 2018暑假校内集训日记
- 暑假集训日记--8.3--搜索
- [暑假集训--数位dp]UESTC250 windy数
- [暑假集训--数论]poj1365 Prime Land
- 贪吃蛇源代码;暑假集训
- 2018寒假福州集训记Day1
- 【2018寒假集训 Day2】【动态规划】垃圾陷阱(挖坑等填,未完成)
- 暑假集训每日总结 第N天 8.8
- 【JZOJ 5241】【GDOI2018模拟8.8】苹果和雪梨
- 暑假集训第1天链表-数据结构上机测试2-1:单链表操作A
- 【FJNUMCS暑假集训周赛#1】
- CSU-ACM2016暑假集训比赛4
- 暑假集训日记--8.11--二分+单调队列
- 暑假集训日记--8.17--树状数组+练习赛
- CSU-ACM2016暑假集训比赛10
- 暑假集训-WHUST 2015 Summer Contest #0.1
- 暑假集训日记--8.19--树状数组