BJOI2015 Day3
(wzj这蒟蒻终于滚Cu了,今天第一题SB题写+调用了1.5h,测试时还WA了一个点。第二题数位DP20分钟写完遇到鬼打墙,中间一切正常最后输出一坨负数。调了1h发现是一个数组开小了。又花了20+min写暴力对拍,大概拍了拍感觉没问题交上去就爆零了2333.最后一道题花10min写个暴力,然后开始写正解,然后,然后,然后写完了却没有调完,最后只能交暴力结果暴力3WA6T,只有10分2333.)
---------------------------------------------------------------------------
T1: http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=497
这是一个博弈游戏,我们可以考虑将当前的n,m记到状态,但可行的(n,m)可能很大,怎么办呢?
注意当m>1时,n最多到sqrt(c)也就是35000+,而当m=1时我们手动分析即可,时间复杂度即为O(sqrt(c)*logc)。
怎么处理Draw的情况呢?注意只有初始n=1且(n+1)^m>=c时两人都不会加n,于是就平局了。(开始这里没有想清楚WA了一个点)
实现时可以看我的code也可以看std的code。我的code用了一个辅助数组t[i]表示最大的指数使i^(t[i])<c来加速判断,相比之下std的可能更好理解。
我的code:
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long LL;
int c,f[][],vis[][];
LL qpow(int n,int m) {
LL ans=,t=n;
while(m) {
if(m&) ans*=t;
t*=t;m>>=;
}
return ans;
}
int t[];
void init() {
memset(t,,sizeof(t));memset(vis,,sizeof(vis));
t[]=c;rep(,) while(qpow(t[i]+,i)<=c) t[i]++;
}
int dp(int n,int m) {
if(n>t[m]) return ;
if(n>t[]) return (c-n)&;
if(n>t[m+]) return (t[m]-n)&;
int& ans=f[n][m];if(vis[n][m]) return ans;
vis[n][m]=;
if(n+<=t[m]&&!dp(n+,m)) return ans=;
if(n<=t[m]+&&!dp(n,m+)) return ans=;
return ans=;
}
int main() {
int T=read();
while(T--) {
int n=read(),m=read();c=read()-;init();
if(n==&&qpow(,m)>c) puts("Draw");
else printf("%s\n",dp(n,m)?"Alice":"Bob");
}
return ;
}
std的code:
#include <cmath>
#include <cstdio>
#include <cstring> using namespace std; const double eps = 1e-;
const int MAXA = , MAXB = ; int set[MAXA][MAXB];
int a, b, n, ret; int solve(int a, int b){
if (a < MAXA && b < MAXB && set[a][b] != ) return set[a][b] - ;
bool A = false, B = false;
if (log(n)/log(a + ) - eps > b) A = true;
if (pow((double)a, b + ) < n - eps) B = true;
int ret = ;
if (!A && !B){
ret = -;
} else if (a == && !A){
ret = ;
} else if (b == && !B){
ret = ((n - a) & ) ? - : ;
} else {
ret = ;
if (B){
int tmp = solve(a, b + ); if (tmp < ret) ret = tmp;
}
if (A){
int tmp = solve(a + , b); if (tmp < ret) ret = tmp;
}
if (ret != ) ret = -ret;
}
if (a < MAXA && b < MAXB) set[a][b] = ret + ;
return ret;
} void print()
{
if (ret == ) printf("Alice\n");
else if (ret == -) printf("Bob\n");
else printf("Draw\n");
} int main()
{
int T;
scanf("%d", &T);
while (T --){
scanf("%d%d%d", &a, &b, &n);
memset(set, , sizeof(set));
ret = solve(a, b);
print();
}
return ;
}
T2:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=498
题意很裸,数位DP。然而我这个蒟蒻在此之前只写过一次数位DP,写起来真是23333.
60分的做法:设f[len][front][sum1][sum2]表示长度为len,开头为front,奇数位之和为sum1,偶数位之和为sum2的方案,转移什么的自己YY或看我的code吧。
加快速度还可以用g[len][front][k]表示长度为len,开头为front,奇数位与偶数位的gcd不超过k的方案。(不过这显然没有什么卵用,我还在这里开小了数组调了1h)
询问考虑差分,将f(l--r)转成f(r)-f(l-1)。考虑之前确定的位对下面没确定的位造成的影响,这个可以看看我的code具体体会。
最后我cal(x)实际求的是[1,x)的幸运数,然后,然后,然后,然后,然后,然后就爆零了。
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long LL;
LL f[][][][],fx[][][];
LL g[][][],xp[];
int preg[][];
int gcd(int a,int b) {return !b?a:gcd(b,a%b);}
void init() {
xp[]=;rep(i,,) xp[i]=xp[i-]*;
rep(i,,) f[][i][i][]=;
rep(i,,) rep(j,,) rep(sum1,,i*) rep(sum2,,i*-sum1) {
if(!f[i][j][sum1][sum2]) continue;
if(!(i&)) rep(k,,) f[i+][k][sum1+k][sum2]+=f[i][j][sum1][sum2];
else rep(k,,) f[i+][k][sum1][sum2+k]+=f[i][j][sum1][sum2];
}
rep(sum1,,) rep(sum2,,) preg[sum1][sum2]=gcd(sum1,sum2);
rep(i,,) rep(j,,) rep(sum1,,i*) rep(sum2,,i*-sum1) {
int t=preg[sum1][sum2];
g[i][j][t]+=f[i][j][sum1][sum2];
}
rep(i,,) rep(j,,) rep(k,,) g[i][j][k]+=g[i][j][k-];
}
int bit[],k;
LL cal(LL x) {
memset(bit,,sizeof(bit));
LL t=x,ans=;int len=,s1=,s2=;
while(t) bit[++len]=t%,t/=;
rep(i,,len-) rep(j,,) ans+=g[i][j][k];
for(int i=len;i;i--) {
rep(j,,bit[i]-) {
if(!j&&i==len) continue;
rep(sum1,,*i) rep(sum2,,*i-sum1)
if(sum1+s1&&sum2+s2&&preg[sum1+s1][sum2+s2]<=k) ans+=f[i][j][sum1][sum2];
}
if(i&) s1+=bit[i];else s2+=bit[i];
}
return ans;
}
int main() {
init();int T=read();
while(T--) {
k=read();LL l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",cal(r+)-cal(l));//cal(r)-cal(l-1) -> WA0 + 2333333
}
return ;
}
100分的做法:设f[len][k][sum1][sum2]表示还有i位没有填写,已填写的与len同奇偶的数位和为sum1,不同奇偶的数位和为sum2,gcd(sum1,sum2)<=k的方案。
f[len][k][sum1][sum2]=sigma{f[len-1][k][sum2-d][sum1]|d=[0,9]},这样询问时就很快了。
注意这里的cal求的是[1,x]
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long LL;
const int maxk=;
LL f[][maxk][maxk][maxk];
int gcd(int a,int b) {return !b?a:gcd(b,a%b);}
void init() {
rep(i,,maxk-) rep(j,,maxk-) rep(k,gcd(i,j),maxk-) f[][k][i][j]=;
rep(i,,) rep(k,,maxk-) {
int mx=(-i)/*;
rep(a,,mx) rep(b,,mx) rep(d,,min(b,)) f[i+][k][b-d][a]+=f[i][k][a][b];
}
}
int bit[],k;
LL cal(LL x) {//[1,x]
if(x<=) return ;
LL t=x,ans=;int len=,s1=,s2=;
while(t) bit[++len]=t%,t/=;
for(int i=len;i;i--) {
rep(j,,bit[i]-)
if(i&) ans+=f[i-][k][s1][s2+j];
else ans+=f[i-][k][s2][s1+j];
if(i&) s2+=bit[i];else s1+=bit[i];
}
return ans+f[][k][s1][s2];
}
int main() {
init();int T=read();
while(T--) {
k=min(read(),);LL l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",cal(r)-cal(l-));//notice!
}
return ;
}
T3:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=499
这是一个比较常规的数据结构题目,首先我们要会求一条链上有多少还没有被删去的点,这个我们可以用DFS序+线段树完成。其次我们发现这道题还带有可持久化操作,那就用可持久化线段树来维护每个版本的DFS序,那么求一条链上有多少还没有被删去的点就成为O(logn)的了。然后我们对于每个询问需要判断被询问点在lca--x上还是在lca--y上,然后二分判断,时间复杂度O(log^2)。
说起来简单写起来还是相当复杂的(我还没写完),先放上std与神犇lxt的AC代码。
std:
#include <vector>
#include <cstdio>
#include <algorithm> using namespace std; const int MAXD = ;
const int MAXN = ; vector <int> adj[MAXN];
bool type[MAXN];
int anc[MAXN][MAXD];
int n, m, root; void init()
{
scanf("%d", &n);
for (int i = ; i <= n; i ++){
scanf("%d", &anc[i][]);
if (!anc[i][]) root = i;
else adj[anc[i][]].push_back(i);
}
} int lt[MAXN], rt[MAXN], dep[MAXN];
bool col[MAXN];//state
int stack[MAXN]; void dfs()
{
int tail = , cnt = ; stack[tail] = root;
while (tail){
int u = stack[tail];
if (!col[u]){
lt[u] = ++ cnt; dep[u] = dep[anc[u][]] + ;
int ts = adj[u].size();
for (int i = ; i < ts; i ++)
stack[++ tail] = adj[u][i];
for (int d = ; d < MAXD; d ++)
anc[u][d] = anc[anc[u][d-]][d-];
col[u] = ;
} else {
rt[u] = ++ cnt; tail --;
}
}
} struct Tseg{
Tseg *lc, *rc;
int l, r, sum;
} pool[MAXN << ]; Tseg *nxt(){
static int cur = ;
return &pool[cur ++];
} Tseg *pos[MAXN], *cur, *lat; #define l(t) (t->lc)
#define r(t) (t->rc) void mktree(Tseg *t, int ll, int rr){
t->l = ll, t->r = rr, t->sum = ;
if (ll == rr) return;
int mid = (ll + rr) >> ;
l(t) = nxt(); mktree(l(t), ll, mid);
r(t) = nxt(); mktree(r(t), mid+, rr);
} #define t_ch tree_change Tseg *t_ch(Tseg *t, int p, int c){
Tseg *ret = nxt(); *ret = *t;
if (t->l == t->r){
ret->sum = c; return ret;
}
if (p <= l(t)->r) l(ret) = t_ch(l(t), p, c);
else r(ret) = t_ch(r(t), p, c);
ret->sum = l(ret)->sum + r(ret)->sum;
return ret;
} int fa(int x, int deep){
if (dep[x] == deep) return x;
for (int d = MAXD-; d >= ; d --)
if (dep[anc[x][d]] >= deep) x = anc[x][d];
return x;
} int find_lca(int x, int y){
if (dep[x] > dep[y]){
int t = x; x = y; y = t;
}
if (dep[x] < dep[y]) y = fa(y, dep[x]);
for (int d = MAXD-; d >= ; d --)
if (anc[x][d] != anc[y][d]) x = anc[x][d], y = anc[y][d];
if (x == y) return x;
return anc[x][];
} #define t_s tree_sum int t_s(Tseg *t, int l, int r){
if (t->l == l && t->r == r) return t->sum;
if (r <= l(t)->r) return t_s(l(t), l, r);
if (l >= r(t)->l) return t_s(r(t), l, r);
return t_s(l(t), l, l(t)->r) + t_s(r(t), r(t)->l, r);
} int check(int x, int y){
return dep[y] - dep[x] + - (t_s(cur, lt[x], lt[y]) - t_s(lat, lt[x], lt[y]));
} int kth(int x, int y, int k){
if (check(x, y) < k) return -;
int l = dep[x], r = dep[y];
while (l < r){
int mid = (l + r) >> ;
int v = fa(y, mid);
int s = check(x, v);
if (s >= k) r = mid;
else l = mid + ;
}
return fa(y, l);
} void print()
{
dfs();
pos[] = nxt(); mktree(pos[], , n << );
scanf("%d", &m);
int type, a, b, c, k, y;
for (int i = ; i <= m; i ++){
scanf("%d", &type);
if (type == ){
scanf("%d", &c);
Tseg *tmp = t_ch(pos[i-], lt[c], );
pos[i] = t_ch(tmp, rt[c], -);
} else {
scanf("%d%d%d%d", &a, &b, &k, &y);
pos[i] = pos[i-]; cur = pos[i]; lat = pos[y];
if (a == anc[b][] || b == anc[a][]){//no castles
puts("-1"); continue;
}
int lca = find_lca(a, b), ans = -;
if (lca != a && lca != b){
int u = anc[a][], v = anc[b][];
int sum = check(lca, u);
if (sum >= k) ans = kth(lca, u, sum - k + );
else ans = v == lca ? - : kth(fa(v, dep[lca] + ), v, k - sum);
} else {
int u, v;
if (lca == a){
u = fa(b, dep[a]+), v = anc[b][];
} else {
u = fa(a, dep[b]+), v = anc[a][];
int sum = check(u, v);
if (sum < k) {puts("-1"); continue;}
k = sum - k + ;
}
ans = kth(u, v, k);
}
printf("%d\n", ans);
}
}
} int main()
{
freopen("travel.in", "r", stdin);
freopen("travel.out", "w", stdout);
init();
print();
return ;
}
lxt:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
#define MAXN 200005
#define MAXT 10000005
using namespace std;
int read(){
int ret = ; char c = getchar();
while(c < '' || c > '') c = getchar();
while(c >= '' && c <= '') {ret *= ; ret += c - ''; c = getchar();}
return ret;
}
int Root, ee, head[MAXN], n, m, fat[MAXN], A, B;
struct Edge{int to, next;}edge[MAXN];
inline void addedge(int x, int y){edge[++ ee].to = y; edge[ee].next = head[x]; head[x] = ee;}
int dep[MAXN], din[MAXN], dout[MAXN], dd, skip[MAXN][];
int dfs(int x){
dep[x] = dep[fat[x]] + ;
din[x] = ++ dd;
skip[x][] = fat[x];
for(int i = ; i <= ; i ++) skip[x][i] = skip[skip[x][i - ]][i - ];
for(int i = head[x]; i != -; i = edge[i].next) dfs(edge[i].to);
dout[x] = ++ dd;
}
int finddep(int x, int dd){
if(dep[x] == dd) return x;
for(int i = ; i >= ; i --) if(dep[skip[x][i]] >= dd) x = skip[x][i];
return x;
}
int cnt, root[MAXN], cl[MAXT], cr[MAXT], s[MAXT];
void insert(int &x, int pre, int l, int r, int p, int c){
x = ++ cnt;
cl[x] = cl[pre], cr[x] = cr[pre], s[x] = s[pre] + c;
if(l == r) return;
int mid = l + r >> ;
if(mid >= p) insert(cl[x], cl[pre], l, mid, p, c);
else insert(cr[x], cr[pre], mid + , r, p, c);
}
int ask(int t, int l, int r, int L, int R){
if(L > R) return ;
if(l >= L && r <= R) return s[t];
int mid = l + r >> , ret = ;
if(L <= mid) ret = ask(cl[t], l, mid, L, R);
if(R >= mid + ) ret += ask(cr[t], mid + , r, L, R);
return ret;
}
inline int LCA(int x, int y){
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; i >= ; i --) if(dep[skip[x][i]] >= dep[y]) x = skip[x][i];
for(int i = ; i >= ; i --) if(skip[x][i] != skip[y][i]) x = skip[x][i], y = skip[y][i];
if(x == y) return x; return skip[x][];
}
int count(int x, int y){
return dep[y] - dep[x] + - ask(B, , * n, din[x], din[y]) + ask(A, , * n, din[x], din[y]);
}
int calck(int x, int y, int k){
if(count(x, y) < k) return -;
int l = dep[x], r = dep[y];
while(l != r){
int mid = l + r >> ;
if(count(x, finddep(y, mid)) >= k) r = mid;
else l = mid + ;
} return finddep(y, l);
}
int main(){
freopen("travel.in", "r", stdin);
freopen("travel.out", "w", stdout);
n = read();
memset(head, -, sizeof(head));
for(int i = ; i <= n; i ++) {fat[i] = read(); if(fat[i]) addedge(fat[i], i); else Root = i;}
dfs(Root);
m = read();
for(int tt = ; tt <= m; tt ++){
int key; key = read();
if(key == ){
int c; scanf("%d", &c);
int la;
insert(la, root[tt - ], , * n, din[c], );
insert(root[tt], la, , * n, dout[c], -);
}else{
root[tt] = root[tt - ];
int a, b, k, y; a = read(); b = read(); k = read(); y = read();
A = root[y], B = root[tt];
if(a == fat[b] || b == fat[a]) {puts("-1"); continue;}
int lca = LCA(a, b);
if(lca != a && lca != b){
int aa = count(lca, fat[a]);
if(aa >= k) {printf("%d\n", calck(lca, fat[a], aa - k + )); continue;}
if(fat[b] == lca) {puts("-1"); continue;}
printf("%d\n", calck(finddep(b, dep[lca] + ), fat[b], k - aa));
} else{
if(lca == a) { printf("%d\n", calck(finddep(b, dep[a] + ), fat[b], k)); continue;}
int la = finddep(a, dep[b] + );
int aa = count(la, fat[a]);
if(aa < k) {puts("-1"); continue;}
printf("%d\n", calck(la, fat[a], aa - k + ));
}
}
}
// system("pause");
return ;
}
BJOI2015 Day3的更多相关文章
- 冲刺阶段day3
day3 项目进展 今天周三,我们五个人难得的一整个下午都能聚在一起.首先我们对昨天的成果一一地查看了一遍,并且坐出了修改.后面的时间则是做出 登录界面的窗体,完善了登录界面的代码,并且实现了其与数据 ...
- BZOJ 4337: BJOI2015 树的同构 树hash
4337: BJOI2015 树的同构 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4337 Description 树是一种很常见的数 ...
- python笔记 - day3
python笔记 - day3 参考:http://www.cnblogs.com/wupeiqi/articles/5453708.html set特性: 1.无序 2.不重复 3.可嵌套 函数: ...
- python_way,day3 集合、函数、三元运算、lambda、python的内置函数、字符转换、文件处理
python_way,day3 一.集合 二.函数 三.三元运算 四.lambda 五.python的内置函数 六.字符转换 七.文件处理 一.集合: 1.集合的特性: 特性:无序,不重复的序列 如果 ...
- Spark菜鸟学习营Day3 RDD编程进阶
Spark菜鸟学习营Day3 RDD编程进阶 RDD代码简化 对于昨天练习的代码,我们可以从几个方面来简化: 使用fluent风格写法,可以减少对于中间变量的定义. 使用lambda表示式来替换对象写 ...
- Spark Tungsten揭秘 Day3 内存分配和管理内幕
Spark Tungsten揭秘 Day3 内存分配和管理内幕 恭喜Spark2.0发布,今天会看一下2.0的源码. 今天会讲下Tungsten内存分配和管理的内幕.Tungsten想要工作,要有数据 ...
- Catalyst揭秘 Day3 sqlParser解析
Catalyst揭秘 Day3 sqlParser解析 今天我们会进入catalyst引擎的第一个模块sqlparser,它是catalyst的前置模块. 树形结构 从昨天的介绍我们可以看到sqlPa ...
- Kakfa揭秘 Day3 Kafka源码概述
Kakfa揭秘 Day3 Kafka源码概述 今天开始进入Kafka的源码,本次学习基于最新的0.10.0版本进行.由于之前在学习Spark过程中积累了很多的经验和思想,这些在kafka上是通用的. ...
- python s12 day3
python s12 day3 深浅拷贝 对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...
随机推荐
- sharepoint部件webparth关闭找回的方法
- maven项目 Java compiler level does not match the version of the installed Java project facet
因工作的关系,Eclipse开发的Java项目拷来拷去,有时候会报一个很奇怪的错误.明明源码一模一样,为什么项目复制到另一台机器上,就会报“java compiler level does not m ...
- sybaseIQ索引类型和使用注意事项
1. FP(Fast Projection)此索引为默认的索引形式,在创建表时系统自动设置此索引. 特点:用于SELECT.LIKE '%sys%'.SUM(A+B).JOIN操作等语句. 此类型索引 ...
- Java for LeetCode 187 Repeated DNA Sequences
All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACG ...
- ubuntu命令行相关命令使用心得
一.Ubuntu解压缩zip,tar,tar.gz,tar.bz2 ZIP zip可能是目前使用得最多的文档压缩格式.它最大的优点就是在不同的操作系统平台,比如Linux, Windows以及Mac ...
- JavaScript封装成类
JavaScript在WEB编程中能起到很大的作用,将一些常用的功能写成JavaScript类库. 将下面代码保存为Common.js 类库功能: 1.Trim(str)--去除字符串两边的空格 2. ...
- Express4--说明
express4.*;(1) var app = express(): 生成一个express实例 app. (2) app.set('views', path.join(__dirname, 'vi ...
- Maximum sum(poj 2479)
题意:给一段数列,将这个数列分成两部分,使两部分的最大子段和的和最大,输出和 /* 看数据没想到是(O)n的算法,求出从前向后的最大子段和和从后向前的最大子段和, 然后枚举断点. 第一次提交不小心折在 ...
- Struts2中配置默认Action
1.当访问的Action不存在时,页面会显示错误信息,可以通过配置默认Action处理用户异常的操作:2.配置方法: 在struts.xml文件中的<package>下添加如下内容: ...
- 【ACM - 搜索模板】
[广搜模板] #include <iostream> #include <stdio.h> #include <string.h> #include <que ...