(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的更多相关文章

  1. 冲刺阶段day3

    day3 项目进展 今天周三,我们五个人难得的一整个下午都能聚在一起.首先我们对昨天的成果一一地查看了一遍,并且坐出了修改.后面的时间则是做出 登录界面的窗体,完善了登录界面的代码,并且实现了其与数据 ...

  2. BZOJ 4337: BJOI2015 树的同构 树hash

    4337: BJOI2015 树的同构 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4337 Description 树是一种很常见的数 ...

  3. python笔记 - day3

    python笔记 - day3 参考:http://www.cnblogs.com/wupeiqi/articles/5453708.html set特性: 1.无序 2.不重复 3.可嵌套 函数: ...

  4. python_way,day3 集合、函数、三元运算、lambda、python的内置函数、字符转换、文件处理

    python_way,day3 一.集合 二.函数 三.三元运算 四.lambda 五.python的内置函数 六.字符转换 七.文件处理 一.集合: 1.集合的特性: 特性:无序,不重复的序列 如果 ...

  5. Spark菜鸟学习营Day3 RDD编程进阶

    Spark菜鸟学习营Day3 RDD编程进阶 RDD代码简化 对于昨天练习的代码,我们可以从几个方面来简化: 使用fluent风格写法,可以减少对于中间变量的定义. 使用lambda表示式来替换对象写 ...

  6. Spark Tungsten揭秘 Day3 内存分配和管理内幕

    Spark Tungsten揭秘 Day3 内存分配和管理内幕 恭喜Spark2.0发布,今天会看一下2.0的源码. 今天会讲下Tungsten内存分配和管理的内幕.Tungsten想要工作,要有数据 ...

  7. Catalyst揭秘 Day3 sqlParser解析

    Catalyst揭秘 Day3 sqlParser解析 今天我们会进入catalyst引擎的第一个模块sqlparser,它是catalyst的前置模块. 树形结构 从昨天的介绍我们可以看到sqlPa ...

  8. Kakfa揭秘 Day3 Kafka源码概述

    Kakfa揭秘 Day3 Kafka源码概述 今天开始进入Kafka的源码,本次学习基于最新的0.10.0版本进行.由于之前在学习Spark过程中积累了很多的经验和思想,这些在kafka上是通用的. ...

  9. python s12 day3

    python s12 day3   深浅拷贝 对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...

随机推荐

  1. 用php实现百度网盘图片直链的代码分享

    第一种代码:代码量较少通过正则表达式获取百度网盘的文件真实地址,来实现直链的效果 将下面的代码保存为downbd.php 复制代码代码如下: <?php $canshu=$_SERVER[&qu ...

  2. mysql中的unsigned

    unsigned   既为非负数,用此类型可以增加数据长度! 例如如果    tinyint最大是127,那    tinyint    unsigned    最大   就可以到    127 * ...

  3. 【leetcode】Palindrome Partitioning

    Palindrome Partitioning Given a string s, partition s such that every substring of the partition is ...

  4. 11.python之线程,协程,进程,

    一,进程与线程 1.什么是线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行 ...

  5. mybatis的insert简单使用

  6. C++动态内存管理之shared_ptr、unique_ptr

    C++中的动态内存管理是通过new和delete两个操作符来完成的.new操作符,为对象分配内存并调用对象所属类的构造函数,返回一个指向该对象的指针.delete调用时,销毁对象,并释放对象所在的内存 ...

  7. show processlist

    mysql> show processlist; #mysql服务器查看有那些主机连进来,并列出它们查什么库 +-----+------+-----------+------+--------- ...

  8. navicat使用跳板机连接数据库-ssh

    1. 目标数据库的域名/IP,端口,用户名,密码:如图1 2. 这时候不要点OK!选择SSH这个tab 3. 选中User SSH Tunnel:填写跳板机域名/IP,用户名,密码(注意:端口22不要 ...

  9. .NET生成word文档服务器配置常见问题

    注意:安装office2003的时候一定要选择 "完全安装" 而不是 "典型安装" 错误:System.Runtime.InteropServices.COME ...

  10. 数据库优化和SQL操作的相关题目

    SQL操作 1.有一个数据库表peope,表有字段name,age,address三个属性(注:没有主键).现在如果表中有重复的数据,请删去重复只留下其中的一条.重复的定义就是两条记录的name,ag ...