NOIP多校联考5
A.旅行日记
错误的更新:
Max = h[1]+d[1]-1; Max = max(Max, h[m]-d[m]+n); for(int i=1; i<m; i++) { Max = max(Max, h[i]); if(d[i+1]-d[i] > 1) { int tmp = h[i+1]-h[i], r = d[i+1]-d[i]; t += tmp; Max = max(Max, h[i+1]+r/2); } }
有卖后悔药的吗?——正确的更新1
Max = h[1]+d[1]-1; Max = max(Max, h[m]-d[m]+n); for(int i=1; i<m; i++) { Max = max(Max, h[i]); if(d[i+1]-d[i] > 1) { int tmp = h[i+1]-h[i], r = d[i+1]-d[i]; r += tmp; Max = max(Max, h[i]+r/2);//其实就是h[i+1]换成了h[i], //这是什么傻乎乎的低错啊!!! } }
正解就在草稿纸上好好的躺着……话说写成这样还有80分,本来应该爆0的……
题解上的式子比我的简单了不少,似乎更容易避免瞎打:——完整版
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 2; const ll mod = 1e9 + 7; const int INF = 0x7ffffff; int n, m, d[maxn], h[maxn], Max; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } bool check() { for(int i=2; i<=m; i++) { if(h[i]-h[i-1] > d[i]-d[i-1]) return 0; } return 1; } int main() { n = read(); m = read(); for(int i=1; i<=m; i++) { d[i] = read(); h[i] = read(); } if(!check()) { printf("IMPOSSIBLE"); exit(0); } Max = h[1]+d[1]-1; Max = max(Max, h[m]-d[m]+n); for(int i=1; i<m; i++) { Max = max(Max, h[i]); if(d[i+1]-d[i] > 1) { int tmp = h[i+1]-h[i], r = d[i+1]-d[i]; r += tmp; Max = max(Max, h[i]+r/2);//其实就是h[i+1]换成了h[i], //这是什么傻乎乎的低错啊!!! } } printf("%d", Max); return 0; }
B.运动
两天之内MLE两次,谁都不服就服你……话说我那个二分过大样例还挺顺的,除了傻乎乎的二维数组开了一堆之外,总感觉他没什么问题……
感觉官方题解就很清楚了:
运动:
单调队列
维护两个单调队列,一个 eggache 值递增,另一个递减。
当两个队头的差大于 k 时,较左的出队,队中元素最左变为出队元素位置+1;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 3e6 + 2; const ll mod = 1e9 + 7; const int INF = 0x7ffffff; int a[maxn], k, n, h1, h2, t1, t2, q1[maxn], ans, q2[maxn], pos; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { //freopen("sport2.in", "r", stdin); k = read(); n = read(); for(int i=1; i<=n; i++) { a[i] = read(); } h1 = 1, h2 = 1, t1 = 0, t2 = 0; pos = 1; for(int i=1; i<=n; i++) { while(t1 >= h1 && a[i] > a[q1[t1]]) t1--; q1[++t1] = i; while(t2 >= h2 && a[i] < a[q2[t2]]) t2--; q2[++t2] = i; while(t1 >= h1 && t2 >= h2 && a[q1[h1]]-a[q2[h2]] > k) { if(q1[h1] < q2[h2]) h1++, pos = q1[h1-1]+1; else h2++, pos = q2[h2-1]+1; } ans = max(ans, i-pos+1); } printf("%d", ans); return 0; }
C.回文
赛时用manacher抢了40分,但是由于机房忽然停电代码没存上,收藏不了了,好可惜哦。
一看题解就恍然大悟,不看题解就迷迷糊糊……
公式真好用,好像不止一次见过这种东西……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 5001; const ll mod = 1e9 + 7; const int INF = 0x7ffffff; char s[maxn]; ll f[maxn][maxn]; ll n, q; bool g[maxn][maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { //freopen("pal2.in", "r", stdin); scanf("%s", s+1); n = strlen(s+1); for(int i=n; i>=1; i--) { g[i][i] = 1; for(int j=i+1; j<=n; j++) { if(s[i] == s[j]) { g[i][j] = g[i+1][j-1]; if(j == i+1) g[i][j] = 1; } } } for(int i=n; i>=1; i--) { for(int j=i; j<=n; j++) { f[i][j] = f[i+1][j]+f[i][j-1]-f[i+1][j-1]+g[i][j]; } } q = read(); while(q--) { int x = read(), y = read(); printf("%lld\n", f[x][y]); } return 0; }
D.基因进化
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 5001; const ll mod = 998244353; const int INF = 0x7ffffff; int T, n, m, a[maxn], b[maxn], c[maxn], d[maxn]; ll ans; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } void work(int num) { int w = 1; while(num) { if(num&1) reverse(d+1, d+w+1); num >>= 1; w++; } } bool nice() { for(int i=1; i<=n; i++) { if(d[i] < c[i]) return 1; else return 0; } return 0; } void Cathy() { for(int i=1; i<=n; i++) { c[i] = d[i]; } } bool check(int num) { for(int i=1; i<=m; i++) { if((1<<(b[i]-1)) & num) return 0; } return 1; } int main() { //freopen("reverse1.in", "r", stdin); T = read(); while(T--) { n = read(); m = read(); ans = 0; for(int i=1; i<=n; i++) { a[i] = read(); c[i] = a[i]; } for(int i=1; i<=m; i++) { b[i] = read(); } int Max = (1<<n); for(int i=1; i<Max; i++) { if(!check(i)) continue; for(int j=1; j<=n; j++) d[j] = a[j]; work(i); if(nice()) Cathy(); } for(int i=n; i>=1; i--) { ans = (ans * 37 % mod + c[i]) % mod; } printf("%lld\n", ans); } return 0; }
把翻转考虑成插入:假设前面的2位操作可得的最小值是AB,我要加入C,一种是BAC,另一种是CAB(ABC->BAC->CAB),再考虑中间有不能翻的,还是AB已确定最小,CD不能翻,我要加入E,一种是ABCDE,另一种是EDCAB(ABCDE->BACDE->EDCAB)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 5001; const ll mod = 998244353; const int INF = 0x7ffffff; bool nrt[300005]; int s[300005], n, m; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } void deal() { for(int i=1; i<=n; i++) { nrt[i] = 0; } n = read(); m = read(); for(int i=1; i<=n; i++) { s[i] = read(); } for(int i=1; i<=m; i++) { int hac = read(); nrt[hac] = 1; } //以下步骤完全模拟每一步的插入和翻转 int tiao = 0; for(int i=2; i<=n; i++)//枚举翻哪位 { if(nrt[i]) { tiao++;//插入的区间的长度-1,i到j之间的数 continue; } int fan = i, zhen = 1;//zhen是开头,fan是现在的位置,两种插入后可能作为起点的情况 int op = 1; bool zhenxiao = 1;//插入的数放后面,情况2 int nct = 0; while(nct <= i) { if(s[fan] > s[zhen]) { zhenxiao = 1; break; } if(s[zhen] > s[fan]) { zhenxiao = 0; break; } //第一位相同,倒着继续往下比 ++nct; ++zhen; if(op) --fan; else ++fan; //如果插入在前面和插入在后面一样,还要继续比较后面,相当于跳到了开头 if(fan == i-tiao-1) op = 0, fan = 1; } if(!zhenxiao)//插到前面==先翻前面再翻整体 { reverse(s+1, s+1+i-tiao-1); reverse(s+1, s+1+i); } tiao = 0; } ll hsh = 0; for(int i=n; i>=1; i--) { hsh = (hsh*37+1ll*s[i])%mod; } printf("%lld\n", hsh); return; } int main() { //freopen("reverse1.in", "r", stdin); int op = read(); while(op--) { deal(); } return 0; }
至于正解……谁来救救我吧……
时光花火,水月星辰