暴力 A - Ebony and Ivory

import java.util.*;
import java.io.*; public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner (new BufferedInputStream (System.in));
int a = cin.nextInt ();
int b = cin.nextInt ();
int c = cin.nextInt ();
for (int i=0; a*i<=c; ++i) {
int d = c - a * i;
if (d % b == 0) {
System.out.println ("Yes");
return ;
}
}
System.out.println ("No");
}
}

数学 B - A Trivial Problem

题意:问n!的后缀0的个数为m个的n的范围.

分析:出现0的一定是2*5产生的,而2的数字有很多,所以找到最小的数字之前5的总个数为m的.二分来找.

#include <bits/stdc++.h>

int number(int x)   {
int ret = 0;
while (x) {
x /= 5;
ret += x;
}
return ret;
} int main() {
int m; scanf ("%d", &m);
int left = 1, right = (int) 1e9;
while (left < right) {
int mid = left + right >> 1;
if (number (mid) < m) left = mid + 1;
else right = mid;
}
std::vector<int> ans;
for (;;) {
if (number (left) == m) ans.push_back (left);
else break;
left++;
}
int sz = ans.size ();
printf ("%d\n", sz);
for (int i=0; i<sz; ++i) {
if (i > 0) putchar (' ');
printf ("%d", ans[i]);
}
puts (""); return 0;
}

Trie + DP C - Spy Syndrome 2

题意:有一句话被变成全小写并且删掉空格并且翻转单词,然后给出可能的单词.问原来可能的这句话.

分析:首先把单词插入到字典树上,这里为了节约内存把所有单词并在一起.结点保存了该单词在单词串的位置以便输出.然后文本串倒过来在字典树上DP搜索,最后正的输出,那么可以找到可行的一句话.

#include <bits/stdc++.h>

const int N = 1e4 + 5;
const int M = 1e6 + 1e5;
const int NODE = M;
char text[N], words[M];
int ch[NODE][26], val[NODE], pos[NODE];
int n, m, sz;
int nex[N], wl[N]; int idx(char c) {
return tolower (c) - 'a';
}
void trie_init() {
memset (ch[0], 0, sizeof (ch[0]));
sz = 1;
}
void trie_insert(char *str, int end, int id, int p) {
int u = 0;
for (int c, i=0; i<end; ++i) {
c = idx (str[i]);
if (!ch[u][c]) {
memset (ch[sz], 0, sizeof (ch[sz]));
val[sz] = 0; pos[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = id; pos[id] = p;
}
void trie_query() {
memset (nex, -1, sizeof (nex));
memset (wl, 0, sizeof (wl));
nex[n] = 0;
for (int i=n; i>0; --i) {
if (nex[i] == -1) continue;
int u = 0;
for (int c, j=i-1; j>=0; --j) {
c = idx (text[j]);
if (!ch[u][c]) break;
u = ch[u][c];
if (val[u] > 0) {
wl[j] = pos[val[u]];
nex[j] = i;
}
}
}
} int main() {
scanf ("%d", &n);
scanf ("%s", text);
scanf ("%d", &m);
trie_init ();
for (int L=0, i=1; i<=m; ++i) {
scanf ("%s", words + L);
int len = strlen (words + L);
trie_insert (words + L, len, i, L);
L += len + 1;
}
trie_query ();
int now = 0;
while (now < n) {
if (now > 0) putchar (' ');
printf ("%s", words + wl[now]);
now = nex[now];
}
puts (""); return 0;
}

DFS + 二分 D - Fibonacci-ish

题意:在n个数找出一组数字满足fn = fn-1 + fn-2, 问最大长度.

分析:n的范围小,可以考虑n^2枚举两个起点,因为要考虑到个数的问题,这里我选择一种方便的写法:首先不考虑个数,只预处理两个数能否到下一个数字.然后考虑个数,类似DFS的vis功能,深搜时-1,回溯时+1

#include <bits/stdc++.h>

const int N = 1e3 + 5;
const int MOD = 1e9 + 7;
int a[N], A[N];
int nex[N][N];
int cnt[N];
int ans; void DFS(int i, int j, int step) {
if (step > ans) ans = step;
int k = nex[i][j];
if (k == -1) return ;
else if (cnt[k] > 0) {
--cnt[k];
DFS (j, k, step + 1);
++cnt[k];
}
} int main() {
int n; scanf ("%d", &n);
for (int i=0; i<n; ++i) {
scanf ("%d", &a[i]); A[i] = a[i];
}
std::sort (A, A+n);
int m = std::unique (A, A+n) - A;
for (int i=0; i<n; ++i) {
a[i] = std::lower_bound (A, A+m, a[i]) - A;
cnt[a[i]]++;
}
for (int i=0; i<m; ++i) {
for (int j=0; j<m; ++j) {
int k = std::lower_bound (A, A+m, A[i] + A[j]) - A;
if (k >= m || A[i] + A[j] != A[k]) nex[i][j] = -1;
else nex[i][j] = k;
}
}
ans = 2;
for (int i=0; i<m; ++i) {
--cnt[i];
for (int j=0; j<m; ++j) {
if (cnt[j] <= 0) continue;
--cnt[j];
DFS (i, j, 2);
++cnt[j];
}
++cnt[i];
}
printf ("%d\n", ans); return 0;
}

二分查找 + RMQ + 组合数学 E - Startup Funding

题意:对于每一个li = i,找到一个ri,使得最大.从n个结果中选择k个,最小值的期望.

分析:第一个问题,考虑前缀max (vk)是递增的,考虑前缀min(ck)是递减的,两者取min那么是单峰函数,二分查找.第二个问题,首先对结果排序,假设最小值为ans[i],那么选中它当最小值的概率是C(n-i, k-1) / C (n, k).p * ans[i]求和就是期望.发现公式可以递推.

#include <bits/stdc++.h>

const int N = 1e6 + 5;
int mx[N][21], mn[N][21];
int best[N];
int n, k; void build_max() {
for (int j=1; (1<<j)<=n; ++j) {
for (int i=1; i+(1<<j)-1<=n; ++i) {
mx[i][j] = std::max (mx[i][j-1], mx[i+(1<<(j-1))][j-1]);
}
}
}
int query_max(int l, int r) {
int k = 0; while (1<<(k+1) <= r-l+1) ++k;
return std::max (mx[l][k], mx[r-(1<<k)+1][k]);
} void build_min() {
for (int j=1; (1<<j)<=n; ++j) {
for (int i=1; i+(1<<j)-1<=n; ++i) {
mn[i][j] = std::min (mn[i][j-1], mn[i+(1<<(j-1))][j-1]);
}
}
}
int query_min(int l, int r) {
int k = 0; while (1<<(k+1) <= r-l+1) ++k;
return std::min (mn[l][k], mn[r-(1<<k)+1][k]);
} int p(int l, int r) {
if (l > r || l < 1 || r > n) return 0;
return std::min (100 * query_max (l, r), query_min (l, r));
} int main() {
scanf ("%d%d", &n, &k);
for (int i=1; i<=n; ++i) {
scanf ("%d", &mx[i][0]);
}
build_max ();
for (int i=1; i<=n; ++i) {
scanf ("%d", &mn[i][0]);
}
build_min ();
for (int i=1; i<=n; ++i) {
int low = i, high = n;
while (low + 1 < high) {
int mid = low + high >> 1;
int v1 = 100 * query_max (i, mid);
int v2 = query_min (i, mid);
if (v1 < v2) low = mid;
else high = mid;
}
best[i-1] = std::max (p (i, low), p (i, high));
}
std::sort (best, best+n);
double prob = 1.0 * k / n;
double ans = prob * best[0];
for (int i=1; i<=n-k; ++i) {
prob = prob * (n - i - k + 1) / (n - i);
ans += prob * best[i];
}
printf ("%.12f\n", ans); return 0;
}

树形DP F - The Chocolate Spree

题意:树上选择两条不相交的路径,且两条路径权值和最大.

分析:因为权值>0, 所以起点或终点一定在叶子结点上,第一次DFS,得到best[u]:u结点的子树下得到最大权值和(一条),以及down[u]:从结点u出发到叶子节点选择一条路的最大权值和.第二次DFS扫描每一个结点,从儿子中选择一个,它子树best[v1]作为一条路径,还有一条从前缀i以及后缀i+1中选择,更新最大值就是答案.

#include <bits/stdc++.h>

typedef long long ll;
const int N = 1e5 + 5;
std::vector<int> edge[N];
int a[N];
ll best[N], down[N];
ll ans;
int n; void DFS(int u, int fa) {
std::vector<ll> downs;
for (auto v: edge[u]) {
if (v == fa) continue;
DFS (v, u);
best[u] = std::max (best[u], best[v]);
downs.push_back (down[v]);
}
ll mx1 = 0, mx2 = 0;
for (auto d: downs) {
if (d > mx1) {
mx2 = mx1; mx1 = d;
}
else if (d > mx2) {
mx2 = d;
}
}
best[u] = std::max (best[u], mx1 + mx2 + a[u]);
down[u] = mx1 + a[u];
ans = std::max (ans, best[u]);
} void DFS2(int u, int fa, ll up) {
up += a[u];
std::vector<int> children;
for (auto v: edge[u]) {
if (v == fa) continue;
children.push_back (v);
}
int sz = children.size ();
if (sz == 0) return ;
std::vector<ll> prebest (sz + 1), sufbest (sz + 1); //前缀(1~i-1)最优的一条路径
prebest[0] = 0;
for (int i=0; i<sz; ++i) {
prebest[i+1] = std::max (prebest[i], best[children[i]]);
}
sufbest[sz] = 0;
for (int i=sz-1; i>=0; --i) { //后缀(i+1~sz-1)最优的一条路径
sufbest[i] = std::max (sufbest[i+1], best[children[i]]);
}
std::vector<ll> predown (sz + 1), predown2 (sz + 1); //前缀两条到叶子节点最优的路径
predown[0] = predown2[0] = 0;
for (int i=0; i<sz; ++i) {
predown[i+1] = predown[i];
predown2[i+1] = predown2[i];
ll x = down[children[i]];
if (x > predown[i+1]) {
predown2[i+1] = predown[i+1];
predown[i+1] = x;
}
else if (x > predown2[i+1]) {
predown2[i+1] = x;
}
}
std::vector<ll> sufdown (sz + 1), sufdown2 (sz + 1); //后缀两条到叶子节点最优的路径
sufdown[sz] = sufdown2[sz] = 0;
for (int i=sz-1; i>=0; --i) {
sufdown[i] = sufdown[i+1];
sufdown2[i] = sufdown2[i+1];
ll x = down[children[i]];
if (x > sufdown[i]) {
sufdown2[i] = sufdown[i];
sufdown[i] = x;
}
else if (x > sufdown2[i]) {
sufdown2[i] = x;
}
}
for (int i=0; i<sz; ++i) {
ll cur = std::max (prebest[i], sufbest[i+1]);
cur = std::max (cur, up + std::max (predown[i], sufdown[i+1]));
cur = std::max (cur, a[u] + predown[i] + sufdown[i+1]);
cur = std::max (cur, a[u] + predown[i] + predown2[i]);
cur = std::max (cur, a[u] + sufdown[i+1] + sufdown2[i+1]);
cur += best[children[i]];
ans = std::max (ans, cur);
}
for (int i=0; i<sz; ++i) {
int v = children[i];
ll new_up = up;
new_up = std::max (new_up, a[u] + std::max (predown[i], sufdown[i+1]));
DFS2 (v, u, new_up);
}
} int main() {
scanf ("%d", &n);
for (int i=1; i<=n; ++i) scanf ("%d", a+i);
for (int u, v, i=1; i<n; ++i) {
scanf ("%d%d", &u, &v);
edge[u].push_back (v);
edge[v].push_back (u);
}
DFS (1, 0);
DFS2 (1, 0, 0);
printf ("%I64d\n", ans); return 0;
}

DFS序 + 线段树 + bitset G - Yash And Trees  

题意:两种操作; 1.v的子树的所有结点权值+x 2. 询问v子树%m后是素数的个数

分析:1操作想到线段树的成段更新,树变成线段用DFS序,每个结点有它'统治"的范围(子树). 然而后者统计用普通数组很难实现.用到了bitset这个容器,里面可以表示m位的01,本题表示一个结点子树所拥有的数值(%m),最后只要&primes就是素数个数.那么如何实现+x呢,因为每一位表示数值,往前一位表示+1,那么<<x, 还有可能移位超出去了,还要| >>(m - x).

#include <bits/stdc++.h>

#define lson l, mid, o << 1
#define rson mid + 1, r, o << 1 | 1
const int N = 1e5 + 5;
std::bitset<1000> tree[N<<2], primes, ret;
std::vector<int> edge[N];
int lazy[N<<2];
int a[N], id[N], fl[N], fr[N];
int n, m, q, tot; void add(int &x, int y) {
x += y;
if (x >= m) x %= m;
} void push_up(int o) {
tree[o] = tree[o<<1] | tree[o<<1|1];
}
void rotate(int o, int x) {
add (lazy[o], x);
tree[o] = (tree[o] << x) | (tree[o] >> (m - x));
}
void push_down(int o) {
if (lazy[o] != 0) {
rotate (o << 1, lazy[o]);
rotate (o << 1 | 1, lazy[o]);
lazy[o] = 0;
}
}
void build(int l, int r, int o) {
if (l == r) {
tree[o].set (a[id[l]]%m); return ;
}
int mid = l + r >> 1;
build (lson); build (rson);
push_up (o);
}
void updata(int ql, int qr, int x, int l, int r, int o) {
if (ql <= l && r <= qr) {
rotate (o, x); return ;
}
push_down (o);
int mid = l + r >> 1;
if (ql <= mid) updata (ql, qr, x, lson);
if (qr > mid) updata (ql, qr, x, rson);
push_up (o);
}
void query(int ql, int qr, int l, int r, int o) {
if (ql <= l && r <= qr) {
ret |= tree[o]; return ;
}
push_down (o);
int mid = l + r >> 1;
if (ql <= mid) query (ql, qr, lson);
if (qr > mid) query (ql, qr, rson);
} void DFS(int u, int fa) {
id[fl[u]=++tot] = u;
for (auto v: edge[u]) {
if (v != fa) DFS (v, u);
}
fr[u] = tot;
} bool is_prime(int x) {
if (x == 2 || x == 3) return true;
if (x % 6 != 1 && x % 6 != 5) return false;
for (int i=5; i*i<=x; i+=6) {
if (x % i == 0 || x % (i + 2) == 0) return false;
}
return true;
} int main() {
scanf ("%d%d", &n, &m);
for (int i=1; i<=n; ++i) {
scanf ("%d", a+i);
}
for (int u, v, i=0; i<n-1; ++i) {
scanf ("%d%d", &u, &v);
edge[u].push_back (v);
edge[v].push_back (u);
}
tot = 0;
DFS (1, 0);
for (int i=2; i<m; ++i) {
if (is_prime (i)) primes.set (i);
}
build (1, n, 1);
scanf ("%d", &q);
while (q--) {
int op, v, x; scanf ("%d%d", &op, &v);
if (op == 1) {
scanf ("%d", &x);
x %= m;
updata (fl[v], fr[v], x, 1, n, 1);
}
else {
ret.reset ();
query (fl[v], fr[v], 1, n, 1);
ret &= primes;
printf ("%d\n", (int) ret.count ());
}
} return 0;
}

暴力 || 莫队+线段树 H - Fibonacci-ish II

题意:q次询问,每次对l和r的范围内的数字去重,然后升序排序,计算fib[j] * a[j]的和.

分析:目前只会暴力的思路: 先排序, 然后每一个数原先对应的询问区间内累加,O(nq)复杂度险过

#include <bits/stdc++.h>

const int N = 3e4 + 5;
std::pair<int, int> a[N];
int fib[N];
int ql[N], qr[N], last[N], step[N];
int ans[N]; int main() {
int n, m; scanf ("%d%d", &n, &m);
for (int i=1; i<=n; ++i) {
scanf ("%d", &a[i].first);
a[i].second = i;
}
std::sort (a+1, a+1+n);
fib[0] = 1; fib[1] = 1;
for (int i=2; i<=n; ++i) fib[i] = (fib[i-2] + fib[i-1]) % m;
int q; scanf ("%d", &q);
for (int i=0; i<q; ++i) {
scanf ("%d%d", ql+i, qr+i);
last[i] = -1;
}
for (int i=1; i<=n; ++i) {
int v = a[i].first % m;
for (int j=0; j<q; ++j) {
if (a[i].second < ql[j] || a[i].second > qr[j]) continue;
if (a[i].first == last[j]) continue;
ans[j] = (ans[j] + v * fib[step[j]++]) % m;
last[j] = a[i].first;
}
}
for (int i=0; i<q; ++i) printf ("%d\n", ans[i]); return 0;
}

  

Manthan, Codefest 16的更多相关文章

  1. Manthan, Codefest 16 D. Fibonacci-ish

    D. Fibonacci-ish time limit per test 3 seconds memory limit per test 512 megabytes input standard in ...

  2. Manthan, Codefest 16(B--A Trivial Problem)

    B. A Trivial Problem time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  3. Manthan, Codefest 16 -C. Spy Syndrome 2

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  4. Manthan, Codefest 16 -A Ebony and Ivory

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  5. CF Manthan, Codefest 16 G. Yash And Trees 线段树+bitset

    题目链接:http://codeforces.com/problemset/problem/633/G 大意是一棵树两种操作,第一种是某一节点子树所有值+v,第二种问子树中节点模m出现了多少种m以内的 ...

  6. CF #Manthan, Codefest 16 C. Spy Syndrome 2 Trie

    题目链接:http://codeforces.com/problemset/problem/633/C 大意就是给个字典和一个字符串,求一个用字典中的单词恰好构成字符串的匹配. 比赛的时候是用AC自动 ...

  7. CF Manthan, Codefest 16 B. A Trivial Problem

    数学技巧真有趣,看出规律就很简单了 wa 题意:给出数k  输出所有阶乘尾数有k个0的数 这题来来回回看了两三遍, 想的方法总觉得会T 后来想想  阶乘 emmm  1*2*3*4*5*6*7*8*9 ...

  8. Manthan, Codefest 16 H. Fibonacci-ish II 大力出奇迹 莫队 线段树 矩阵

    H. Fibonacci-ish II 题目连接: http://codeforces.com/contest/633/problem/H Description Yash is finally ti ...

  9. Manthan, Codefest 16 E. Startup Funding ST表 二分 数学

    E. Startup Funding 题目连接: http://codeforces.com/contest/633/problem/E Description An e-commerce start ...

随机推荐

  1. Linux中LoadAverage分析

    判断系统负荷 1.uptime 命令,load average的三个数分别表示了1分钟.5分钟.15分钟的平均进程数. 如果你继续看手册,它还会告诉你,当CPU完全空闲的时候,平均负荷为0:当CPU工 ...

  2. 将rabbitmq整合到Spring中手动Ack

    如果要手动ack,需要将Listener container 的 acknowledge 设置为manul,在消费消息的类中需实现ChannelAwareMessageListener接口. over ...

  3. PHP面向对象——异常处理

    Error_reporting(0);  //在网站正式上线的时候不准他报任何错误.  错误级别为不允许报错 Exception 是所有异常的基类. 测试并捕捉一个错误的例子:  class mysq ...

  4. 利用bak文件恢复数据库问题小结

    对备份的基础理解: --完整备份:完整备份会备份所有数据的区和少量的日志(日志文件用于恢复数据保持数据一致性).由于差异备份需要依据最后一次完整备份,因此完整备份会清楚一些分配位图数据. --差异备份 ...

  5. JAVA基础学习之IP简述使用、反射、正则表达式操作、网络爬虫、可变参数、了解和入门注解的应用、使用Eclipse的Debug功能(7)

    1.IP简述使用//获取本地主机ip地址对象.InetAddress ip = InetAddress.getLocalHost();//获取其他主机的ip地址对象.ip = InetAddress. ...

  6. Linux Shell 高级编程技巧4----几个常用的shell脚本例子

    4.几个常用的shell脚本例子    4.0.在写脚本(同样适用在编程的时候),最好写好完善的注释    4.1.kill_processes.sh(一个杀死进程的脚本) #!/bin/bash c ...

  7. php array_intersect() 和 array_diff() 函数

    在PHP中,使用 array_intersect 求两个数组的交集比使用 array_diff 求同样两个数组的并集要快. 如果要求数组 $a 与数组 $b 的差集的个数,应该使用 count($a) ...

  8. PHP保留小数位的三种方法

    /** * PHP保留两位小数的几种方法 * @link http://www.phpddt.com */ $num = 10.4567; //第一种:利用round()对浮点数进行四舍五入 echo ...

  9. gdb调试小结

    gdb最基本的调试命令. 1以调试程序test.cpp为例: 进入调试环境 gdb test 2.b 12 在文件的第12行设置断点. 删除断点: info b 列出所有的断点信息 (gdb) inf ...

  10. hdu 5833 Zhu and 772002 高斯消元

    Zhu and 772002 Problem Description Zhu and 772002 are both good at math. One day, Zhu wants to test ...