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; }
B
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; }
C
贪心构造,画一下就知道,炸一个格子会把剩余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; }