暴力 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. August 19th 2016 Week 34th Friday

    Friends are not the people you meet at the top, they are the people who were with you at the bottom. ...

  2. UVa1592_数据库

    #include<iostream> #include<cstdio> #include<vector> #include<utility> #incl ...

  3. linux rpm问题:怎样查看rpm安装包的安装路径

      x rpm问题:怎样查看rpm安装包的安装路径 2010-07-12 21:19:15 标签:rpm linux 路径 休闲 职场 rpm -qpl xxxxxx.rpm 1.如何安装rpm软件包 ...

  4. JDBC之SqlHelper

    SqlHelper工具类如下: import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.Resul ...

  5. 二、JavaScript语言--JS实践--商城分类导航效果

    商城类导航菜单制作(以京东为例--竖向列表横向伸缩) 可以用两种方式来实现:用CSS实现和用JS实现 方法一:用CSS实现(要点:使用hover) <!DOCTYPE html PUBLIC & ...

  6. iOS,Objective-C,相册功能的实现。

    #import "ViewController.h" #define kuan [UIScreen mainScreen].bounds.size.width #define ga ...

  7. php 用户登录验证

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. 公众号开发——测试工具【ngrok】

    工具下载:ngrok 目录清单: ngrok.exe ngrok.cfg run.bat 点击bat启动. 可修改域名,右键bat文件修改. 成功效果图: 注:80端口被占用了怎么办?    ——   ...

  9. NPOI读写Excel

    1.整个Excel表格叫做工作表:WorkBook(工作薄),包含的叫页(工作表):Sheet:行:Row:单元格Cell. 2.NPOI是POI的C#版本,NPOI的行和列的index都是从0开始 ...

  10. python生成RSS(PyRSS2Gen)

    既然能够用python解析rss,那么也顺带研究下生成rss. 其实很简单,只是生成一个比较特殊点的xml文档而已. 这里我使用了PyRss2Gen,用法很简单,看代码就知道了,如下: import ...