d1t1[HNOI/AHOI2018]寻宝游戏

感觉很神,反正我完全没想到

分开考虑每一位,对于每一位i计算一个二进制数b[i],

对于第i位,从后往前第j个数这一位是1,那么b[i]^=(1<<j)

对于操作,从后往前考虑每个数前面的符号,把&看成1,|看成0

把一个操作序列看成一个二进制数c

发现|0和&1等于无影响,一个操作序列的最后一个|1或者&0决定结果的值

那么对于第i位,要使这一位为1,必须满足c<b[i]

(这一位是1,则要选择一个b[i]中是1的位置取|,并将它之前的所有操作任意取,之后的操作有唯一取法,相当于将二进制位中某个1变成0,高位不变,低位任意取,最后得到c<b[i])

那么将b从大到小排序,对于每个询问,首先满足找到最靠左的0必须在1后面,然后最靠左的0的位置为pos,答案为b[pos-1]-b[pos]

要取模,一开始傻乎乎地在那里写高精...

 //Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=,mod=1e9+;
typedef long long LL;
typedef double db;
using namespace std;
const LL mxup=(1LL<<);
int n,m,q,sa[N],rak[N],L;
LL ans[N];
char s[][N],ss[N]; template<typename T>void read(T &x) {
char ch=getchar(); x=; T f=;
while(ch!='-'&&(ch<''||ch>'')) ch=getchar();
if(ch=='-') f=-,ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) x=x*+ch-''; x*=f;
} bool cmp(const int &A,const int &B) {
Rep(i,n,) {
if(s[i][A]!=s[i][B]) return s[i][A]>s[i][B];
} return ;
} void pre() {
For(i,,m)
Rep(j,n,) {
int x=i==?:s[j][i]-'';
ans[i]=((ans[i]<<)%mod+x)%mod;
}
ans[]=(ans[]+)%mod;
} //#define DEBUG
int main() {
#ifdef DEBUG
freopen("hunt.in","r",stdin);
freopen("hunt.out","w",stdout);
#endif
read(n); read(m); read(q);
For(i,,n) scanf("%s",s[i]+);
For(i,,m) sa[i]=i;
sort(sa+,sa+m+,cmp);
For(i,,m) rak[sa[i]]=i;
pre();
while(q--) {
int ll=,rr=m+;
scanf("%s",ss+);
For(i,,m) {
int x; x=ss[i]-'';
if(x==) ll=max(ll,rak[i]);
else if(!rr||rr>rak[i]) rr=rak[i];
}
if(rr<ll) puts("");
else {
LL rs=(rr==m+?ans[sa[rr-]]:(ans[sa[rr-]]-ans[sa[rr]]+mod)%mod);
printf("%lld\n",rs);
}
}
return ;
}
/*
5 5 1
01110
11011
10000
01010
00100
00100
*/

d1t2[HNOI/AHOI2018]转盘

贪心.发现一定有一种最优答案是在某个起点待着不动一会,然后一路走下去

考虑如果答案是走了很多圈,最后一个取的点为x,那么从最后时刻从x往前走一圈,一路上所有东西肯定都是已经出现了的,把游戏倒过来,就是从x往前走,在每个物品消失前取到它,那么最优策略一定是从x一步不停地走下去,那么正过来也是一样.

把原序列倍长,答案就等于 

$ans=min_{i=1}^n(max_{j=i}^{2*n}T[j]-(j-i)+n-1)$

$设A[i]=T[i]-i$

$ans=min_{i=1}^n(max_{j=i}^{2*n}A[j]+i)+n+1$

维护和楼房重建很像.

用线段树维护答案,线段树上分别维护A[i]的最大值,和在l~r这段区间中来算(即n=r,i=l~n),i在l~mid中的答案的最小值

支持询问qry(x,l,r,suf)表示i在l,r这段去就,A[i]和suf取max后的答案,那么修改时可以调用qry在两个log的时间里更新线段树里的值

注意询问时直接输出线段树中根的答案,而不是调用qry(suf会出问题),

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=;
typedef long long LL;
typedef double db;
using namespace std;
int n,m,p,T[N],A[N],ans; template<typename T> void read(T &x) {
char ch=getchar(); x=; T f=;
while(ch!='-'&&(ch<''||ch>'')) ch=getchar();
if(ch=='-') f=-,ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) x=x*+ch-''; x*=f;
} #define lc x<<1
#define rc ((x<<1)|1)
#define mid ((l+r)>>1)
int mx[N<<],sg[N<<];
int qry(int x,int l,int r,int suf) {
if(l==r) return max(suf,mx[x])+l;
if(mx[rc]>=suf) return min(sg[x],qry(rc,mid+,r,suf));
else return min(qry(lc,l,mid,suf),suf+mid+);
} void update(int x,int l,int r) {
mx[x]=max(mx[lc],mx[rc]);
sg[x]=qry(lc,l,mid,mx[rc]);
} void change(int x,int l,int r,int pos) {
if(l==r) {
mx[x]=A[l]; sg[x]=A[l]+l; return;
}
if(pos<=mid) change(lc,l,mid,pos);
else change(rc,mid+,r,pos);
update(x,l,r);
} void build(int x,int l,int r) {
if(l==r) { mx[x]=A[l]; sg[x]=A[l]+l; return; }
build(lc,l,mid); build(rc,mid+,r);
update(x,l,r);
} //#define DEBUG
int main() {
#ifdef DEBUG
freopen("circle.in","r",stdin);
freopen("circle.out","w",stdout);
#endif
read(n); read(m); read(p);
For(i,,n) {
read(T[i]); A[i]=T[i]-i;
T[i+n]=T[i]; A[i+n]=T[i+n]-(i+n);
}
build(,,n*);
ans=sg[]+n-;
printf("%d\n",ans);
For(i,,m) {
int x,y;
read(x); read(y);
if(p) x^=ans,y^=ans;
T[x]=y; A[x]=T[x]-x;
change(,,n*,x);
T[x+n]=y; A[x+n]=T[x+n]-(x+n);
change(,,n*,x+n);
ans=sg[]+n-;
printf("%d\n",ans);
}
return ;
}

d1t3[HNOI/AHOI2018]毒瘤

如果给出的一棵树,可以直接树dp,时间复杂度O(n)

发现非树边很少,可以枚举非树边上的点的状态,然后dp,时间复杂度为2^d*n(只用枚举每条非树边中一个点的状态)

考虑优化这个算法,发现每次树dp只有非树边上的点有影响,重复计算了很多没有必要的过程

那么把非树边拿出来建虚树,每次在虚树上dp

先对原树dp一次求出在虚树上dp要用到的系数

设g[x][0/1]表示常数,即x的那些没有任何关键点的儿子的贡献.

k[x][0/1][0/1]表示我对于我下面(包括我)第一个关键点的转移系数

即(设我下面第一个关键点为w) 

f[x][0]= k[x][0][0]*f[w][0]+k[x][0][1]*f[w][1];

f[x][1]= k[x][1][0]*f[w][0]+k[x][1][1]*f[w][1];

边界为若我为关键点,

k[x][0][0]=1,k[x][0][1]=0;

k[x][1][0]=0,k[x][1][1]=1;

dp出k和g,就可以在虚树上转移了

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=,p=;
typedef long long LL;
typedef double db;
using namespace std;
int n,m,eu[N],ev[N],tot; template<typename T> void read(T &x) {
char ch=getchar(); x=; T f=;
while(ch!='-'&&(ch<''||ch>'')) ch=getchar();
if(ch=='-') f=-,ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) x=x*+ch-''; x*=f;
} int ecnt,fir[N],nxt[N<<],to[N<<];
void add(int u,int v) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
} int sz[N],is[N],vis[N];
void dfs(int x,int fa) {
vis[x]=;
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
if(!vis[to[i]]) {
dfs(to[i],x);
sz[x]+=sz[to[i]];
}
else {
is[x]=;
if(to[i]<x) eu[++tot]=x,ev[tot]=to[i];
}
}
is[x]=(is[x]||sz[x]>=);
sz[x]=(sz[x]||is[x]);
} struct pt {
LL a,b;
pt(){}
pt(int a,int b):a(a),b(b){}
friend pt operator +(const pt&A,const pt&B) {
return pt((A.a+B.a)%p,(A.b+B.b)%p);
}
friend pt operator *(const pt&A,const LL&B) {
return pt(A.a*B%p,A.b*B%p);
}
}k[N][]; struct edge {
int u,v,nx;
pt x,y;
edge(){}
edge(int u,int v,pt x,pt y,int nx):u(u),v(v),x(x),y(y),nx(nx){}
}e[N]; int fi[N],ec;
void ADD(int u,int v,pt x,pt y) {
e[++ec]=edge(u,v,x,y,fi[u]); fi[u]=ec;
} LL g[N][],bx[N][],f[N][],ans;
int pre(int x,int fa) {
vis[x]=;
g[x][]=g[x][]=;
int rs=;
if(x==) {
int debug=;
}
for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) {
int w=pre(to[i],x); if(!rs) rs=w;
if(!w) {
g[x][]=g[x][]*((g[to[i]][]+g[to[i]][])%p)%p;
g[x][]=g[x][]*g[to[i]][]%p;
}
else if(is[x]) ADD(x,w,k[to[i]][]+k[to[i]][],k[to[i]][]);
else k[x][]=k[to[i]][]+k[to[i]][],k[x][]=k[to[i]][];
}
if(is[x]) k[x][]=pt(,),k[x][]=pt(,);
else k[x][]=k[x][]*g[x][],k[x][]=k[x][]*g[x][];
if(is[x]) rs=x;
return rs;
} void dp(int x) {
f[x][]=bx[x][]?:g[x][];
f[x][]=bx[x][]?:g[x][];
for(int i=fi[x];i;i=e[i].nx) {
int v=e[i].v;
pt a=e[i].x,b=e[i].y;
dp(v);
f[x][]=(f[x][]*(a.a*f[v][]%p+a.b*f[v][]%p))%p;
f[x][]=(f[x][]*(b.a*f[v][]%p+b.b*f[v][]%p))%p;
}
} //#define DEBUG
int main() {
#ifdef DEBUG
freopen("duliu.in","r",stdin);
freopen("duliu.out","w",stdout);
#endif
read(n); read(m);
For(i,,m) {
int u,v;
read(u); read(v);
add(u,v);
}
dfs(,); is[]=;
memset(vis,,sizeof(vis));
pre(,);
int nn=(<<tot)-;
For(i,,nn) {
For(j,,tot) {
if(i&(<<j-)) {
bx[eu[j]][]=; bx[ev[j]][]=;
}
else bx[eu[j]][]=;
}
dp();
ans=((ans+f[][])%p+f[][])%p;
For(j,,tot) {
if(i&(<<j-)) {
bx[eu[j]][]=; bx[ev[j]][]=;
}
else bx[eu[j]][]=;
}
}
printf("%lld\n",ans);
return ;
}
/*
12 17
12 3
12 5
11 12
7 5
5 10
1 5
5 8
8 7
11 9
3 6
10 1
1 9
1 7
12 4
2 9
11 2
7 3
*/

d2t1游戏

sxy的做法:

  一个点能走到的是一段区间,记为l[x],r[x]

  若一段路的钥匙在左端点及左边,那么只能从左走到右,从左到右连单向边.

  若钥匙在右端点及右边,那么只能从右走到左,单向边

  否则连双向边.预处理出这些边都能走的情况下左右最远走到哪里,记为ld,rd

  然后从左到右计算l,r,

  1.若我可以到左边,且钥匙在我这里或者不需要钥匙,那么l[x]=l[x-1],r[x]=r[x-1]

  2.若我到不了左边,在x~rd[x]中二分一个位置pos,使这从x到pos这一段的每一个位置的钥匙都在从x到它之间,l[x]=x,r[x]=pos

  3.我能到左边,拿不到钥匙.先和2一样二分一个pos,看在这一段中能不能拿到左边的钥匙,l[x]拓展到l[x-1],拿到这一段钥匙后继续往右边二分,然后再试图向左拓展

    发现每次向左拓展的点一定是之前未拓展到的,那么每条向左的边最多会使我向左拓展一次,每次向右拓展复杂的是一个log,总复杂的nlogn

我的一个及其蠢的做法:

  发现如果从x能走到y(假使x在y左边,右边同理),设x到y的路径上最靠左的钥匙位置在z,走过的路径即为z,x,y这一段

  这一段路径要能走需要满足,x到y路径上任意一个点a,它的钥匙在的地方b,从x到b的每个点的钥匙必须在它右边且在a左边

  那么对于每个点x,它的钥匙在它左边的y,可以二分一个最靠右的z使y到z的路径上所有点的钥匙都在自己的右边且在x的左边,记录这个最靠右的位置为rans[x]

  那么x能走到y需要满足从x到y的rans都大于x

  对于rans可以用线段树记录所有点钥匙所在的位置,在线段树上二分,求出rans后第二个问题可以用线段树解决.

  同理考虑左边的lans

  x在y右边的情况同理

  时间复杂度nlogn,然而常数巨大..本机卡常卡过了,洛谷t了两个点

 // luogu-judger-enable-o2
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
const int N=1e6+;
typedef long long LL;
typedef double db;
using namespace std;
int n,m,q,yl[N]; template<typename T> void read(T &x) {
char ch=getchar(); x=; T f=;
while(ch!='-'&&(ch<''||ch>'')) ch=getchar();
if(ch=='-') f=-,ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) x=x*+ch-''; x*=f;
} #define lc x<<1
#define rc ((x<<1)|1)
#define mid ((l+r)>>1)
int mx[N<<],mi[N<<];
inline void build(int x,int l,int r) {
if(l==r) {
mx[x]=mi[x]=yl[l];
if(yl[l]==) mx[x]=,mi[x]=n+;
return;
}
build(lc,l,mid); build(rc,mid+,r);
mx[x]=max(mx[lc],mx[rc]);
mi[x]=min(mi[lc],mi[rc]);
} inline int qryl(int x,int l,int r,int ql,int qr,int v) {
if(l>=ql&&r<=qr) {
if(mx[x]<=v) return r;
if(l==r) return ;
if(mx[lc]<=v) {
int rs=qryl(rc,mid+,r,ql,qr,v);
if(!rs) rs=mid;
return rs;
}
else return qryl(lc,l,mid,ql,qr,v);
}
int rs=;
if(ql>mid) return qryl(rc,mid+,r,ql,qr,v);
if(qr<=mid) return qryl(lc,l,mid,ql,qr,v);
else {
rs=qryl(lc,l,mid,ql,qr,v);
int rs2=;
if(rs==mid) rs2=qryl(rc,mid+,r,ql,qr,v);
if(rs2) rs=rs2;
return rs;
}
} inline int qryr(int x,int l,int r,int ql,int qr,int v) {
if(l>=ql&&r<=qr) {
if(mi[x]>=v) return l;
if(l==r) return ;
if(mi[rc]>=v) {
int rs=qryr(lc,l,mid,ql,qr,v);
if(!rs) rs=mid+;
return rs;
}
else return qryr(rc,mid+,r,ql,qr,v);
}
int rs=;
if(ql>mid) return qryr(rc,mid+,r,ql,qr,v);
if(qr<=mid) return qryr(lc,l,mid,ql,qr,v);
else {
rs=qryr(rc,mid+,r,ql,qr,v);
int rs2=;
if(rs==mid+) rs2=qryr(lc,l,mid,ql,qr,v);
if(rs2) rs=rs2;
return rs;
}
} int lans[N],rans[N];
int sgmi[N<<],sgmx[N<<];
inline void build2(int x,int l,int r) {
if(l==r) { sgmi[x]=rans[l]; sgmx[x]=lans[l]; return; }
build2(lc,l,mid); build2(rc,mid+,r);
sgmi[x]=min(sgmi[lc],sgmi[rc]);
sgmx[x]=max(sgmx[lc],sgmx[rc]);
} inline int qrymi(int x,int l,int r,int ql,int qr,int sg[]) {
if(l>=ql&&r<=qr) return sg[x];
if(qr<=mid) return qrymi(lc,l,mid,ql,qr,sg);
if(ql>mid) return qrymi(rc,mid+,r,ql,qr,sg);
return min(qrymi(lc,l,mid,ql,qr,sg),qrymi(rc,mid+,r,ql,qr,sg));
} inline int qrymx(int x,int l,int r,int ql,int qr,int sg[]) {
if(l>=ql&&r<=qr) return sg[x];
if(qr<=mid) return qrymx(lc,l,mid,ql,qr,sg);
if(ql>mid) return qrymx(rc,mid+,r,ql,qr,sg);
return max(qrymx(lc,l,mid,ql,qr,sg),qrymx(rc,mid+,r,ql,qr,sg));
} //#define DEBUG
int main() {
#ifdef DEBUG
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
#endif
read(n); read(m); read(q);
For(i,,m) {
int x,y;
read(x); read(y);
yl[x]=y;
}
build(,,n-);
For(i,,n) {
if(yl[i]==) {
lans[i]=;
rans[i]=n+;
}
else {
if(yl[i]>i)
lans[i]=qryr(,,n-,,yl[i]-,i+);
else lans[i]=n+;
if(yl[i]<=i)
rans[i]=qryl(,,n-,yl[i],n,i);
else rans[i]=;
}
}
build2(,,n-);
For(i,,q) {
int x,y;
read(x); read(y);
if(x==y) puts("YES");
else if(x<=y) {
int z=qrymi(,,n-,x,y-,mi);
int tp1=qrymi(,,n-,x,y-,sgmi);
int tp2=z>x-?x:qrymx(,,n-,z,x-,sgmx);
if(tp1>=max(,x-)&&tp2<=min(n,x+)) puts("YES");
else puts("NO");
}
else {
int z=qrymx(,,n-,y,x-,mx);
int tp2=qrymx(,,n-,y,x-,sgmx);
int tp1=z-<x?x:qrymi(,,n-,x,z-,sgmi);
if(tp1>=max(,x-)&&tp2<=min(n,x+)) puts("YES");
else puts("NO");
}
}
return ;
}

正解:按sxy的做法把图建出来后,按拓扑序拓展,似乎就可以直接做到O(n)了

d2t2排列

读题读好久..转换过来就是,给一棵树,父亲必须比儿子先选,选出来的序列记为p,答案为i*p[i]的和

贪心

考虑合并两段区间a,b,区间内已经合并好了,若a放在b前面更优,则说明len[a]*val[b]>len[b]*val[a]

即len[a]/val[a]>len[b]/val[b];

那么优先队列存每段区间的len和val,每次取出队首和父亲合并即可.

 //Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=;
typedef long long LL;
typedef double db;
using namespace std;
int n,a[N],w[N],fa[N],len[N];
LL sum[N]; template<typename T> void read(T &x) {
char ch=getchar(); x=; T f=;
while(ch!='-'&&(ch<''||ch>'')) ch=getchar();
if(ch=='-') f=-,ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) x=x*+ch-''; x*=f;
} struct node {
int x,sz; LL sum;
node(int x,int sz,LL sum):x(x),sz(sz),sum(sum){}
friend bool operator <(const node&A,const node&B) {
return A.sz*B.sum<B.sz*A.sum;
}
}; int ecnt,fir[N],nxt[N],to[N],in[N];
void add(int u,int v) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; in[v]++;
} queue<int>q;
LL tpsort() {
int tot=;
For(i,,n) if(!in[i]) q.push(i);
while(!q.empty()) {
int x=q.front();
q.pop();
tot++;
for(int i=fir[x];i;i=nxt[i]) {
in[to[i]]--;
if(!in[to[i]]) q.push(to[i]);
}
}
if(tot!=n) return -;
return ;
} int f[N];
int find(int x) { return x==f[x]?f[x]:f[x]=find(f[x]); } priority_queue<node>que;
LL solve() {
LL rs=;
For(i,,n) rs+=w[i],f[i]=i;
while(!que.empty()) {
node tp=que.top();
que.pop();
if(tp.sz!=len[tp.x]) continue;
int F=find(fa[tp.x]);
rs+=sum[tp.x]*len[F];
sum[F]+=sum[tp.x];
len[F]+=len[tp.x];
f[tp.x]=F;
if(F) que.push(node(F,len[F],sum[F]));
}
return rs;
} //#define DEBUG
int main() {
#ifdef DEBUG
freopen("perm.in","r",stdin);
freopen("perm.out","w",stdout);
#endif
read(n);
For(i,,n) {
read(a[i]);
if(a[i]) { fa[i]=a[i]; add(a[i],i); }
}
For(i,,n) read(w[i]);
if(tpsort()==-) puts("-1");
else {
For(i,,n) {
sum[i]=w[i]; len[i]=;
que.push(node(i,,sum[i]));
}
printf("%lld\n",solve());
}
return ;
}

d2t3[HNOI/AHOI2018]道路

一道水题,直接树形dp,记录上面的公路和铁路的条数.

一开始不知道为什么以为是满二叉树,空间炸了.

深度有40,不炸空间要开map存.

 //Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=;
typedef long long LL;
typedef double db;
using namespace std;
LL n,a[N],b[N],c[N],gls[N],tls[N];
map<int,LL>dp[N]; template<typename T> void read(T &x) {
char ch=getchar(); x=; T f=;
while(ch!='-'&&(ch<''||ch>'')) ch=getchar();
if(ch=='-') f=-,ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) x=x*+ch-''; x*=f;
} void add(int u,int v,int o) {
if(!o) gls[u]=v;
else tls[u]=v;
} void dfs(int x,int l1,int l2) { //i gonglu
if(!gls[x]) {
For(i,,l1) For(j,,l2) dp[x][i*+j]=c[x]*(a[x]+i)*(b[x]+j);
return ;
}
int gl=gls[x],tl=tls[x];
dfs(gl,l1+,l2); dfs(tl,l1,l2+);
For(i,,l1) For(j,,l2)
dp[x][i*+j]=min(dp[gl][i*+j]+dp[tl][i*+j+],dp[gl][(i+)*+j]+dp[tl][i*+j]);
} //#define DEBUG
int main() {
#ifdef DEBUG
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
#endif
read(n);
For(i,,n-) {
int si,ti;
read(si); read(ti);
if(si>) add(i+n,n+si,);
else add(i+n,-si,);
if(ti>) add(i+n,n+ti,);
else add(i+n,-ti,);
}
For(i,,n) { read(a[i]); read(b[i]); read(c[i]); }
dfs(+n,,);
printf("%lld\n",dp[n+][]);
return ;
}
/*
6
2 3
4 5
-1 -2
-3 -4
-5 -6
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1 9
2 -2
3 -3
4 -4
5 -5
6 -6
7 -7
8 -8
-1 -9
1 60 1
1 60 1
1 60 1
1 60 1
1 60 1
1 60 1
1 60 1
1 60 1
1 60 1 12
2 4
5 3
-7 10
11 9
-1 6
8 7
-6 -10
-9 -4
-12 -5
-2 -3
-8 -11
53 26 491
24 58 190
17 37 356
15 51 997
30 19 398
3 45 27
52 55 838
16 18 931
58 24 212
43 25 198
54 15 172
34 5 524
*/

Orz cai大佬day2AK进队

Orz sxyday2AK吊打我这种辣鸡滚粗选手

你们都太强啦%%%

HNOI2018的更多相关文章

  1. Loj #2495. 「AHOI / HNOI2018」转盘

    Loj #2495. 「AHOI / HNOI2018」转盘 题目描述 一次小 G 和小 H 原本准备去聚餐,但由于太麻烦了于是题面简化如下: 一个转盘上有摆成一圈的 \(n\) 个物品(编号 \(1 ...

  2. Loj #2494. 「AHOI / HNOI2018」寻宝游戏

    Loj #2494. 「AHOI / HNOI2018」寻宝游戏 题目描述 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得 ...

  3. 【HNOI2018】排列

    [HNOI2018]排列 神仙贪心题. 题目说这么大堆东西就是想告诉你这是个森林,选了\(v\)的父亲后才能选\(v\). 我们设\(w_v\)为\(v\)所在联通块权值和,\(size_v\)表示\ ...

  4. 【HNOI2018】毒瘤

    [HNOI2018]毒瘤 设\(f_{v,0}\)表示\(v\)的子树中\(v\)不选的方案数,\(f_{v,1}\)表示\(v\)选的方案数. 显然 \[ f_{v,0}=\prod (f_{sn, ...

  5. 【BZOJ5285】[HNOI2018]寻宝游戏(神仙题)

    [BZOJ5285][HNOI2018]寻宝游戏(神仙题) 题面 BZOJ 洛谷 题解 既然是二进制按位的运算,显然按位考虑. 发现这样一个关系,如果是\(or\)的话,只要\(or\ 1\),那么无 ...

  6. 【BZOJ5289】[HNOI2018]排列(贪心)

    [BZOJ5289][HNOI2018]排列(贪心) 题面 BZOJ 洛谷 题解 这个限制看起来不知道在干什么,其实就是找到所有排列\(p\)中,\(p_k=x\),那么\(k<j\),其中\( ...

  7. 【BZOJ5288】[HNOI2018]游戏(拓扑排序)

    [BZOJ5288][HNOI2018]游戏(拓扑排序) 题面 BZOJ 洛谷 题解 去年省选的时候这题给我乱搞整过去整过去了,也是虐心了.... 所以当然是来讲正儿八经的正确做法啦. 很明显,我们需 ...

  8. 【BZOJ5287】[HNOI2018]毒瘤(动态规划,容斥)

    [BZOJ5287][HNOI2018]毒瘤(动态规划,容斥) 题面 BZOJ 洛谷 题解 考场上想到的暴力做法是容斥: 因为\(m-n\le 10\),所以最多会多出来\(11\)条非树边. 如果就 ...

  9. HNOI2018做题笔记

    HNOI2018 寻宝游戏(位运算.基数排序) 看到位运算就要按位考虑.二进制下,\(\land 1\)与\(\lor 0\)没有意义的,\(\land 0\)强制这一位变为\(0\),\(\lor ...

  10. HNOI2018简要题解

    HNOI2018简要题解 D1T1 寻宝游戏 题意 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为 ...

随机推荐

  1. ADIS16405BMLZ

    GND,VCC,CS,DOUT,SCLK,DIN

  2. log4j架构

    Log4j API设计为分层结构,其中每一层提供了不同的对象,对象执行不同的任务.这使得设计灵活,根据将来需要来扩展. 有两种类型可用在Log4j的框架对象. 核心对象: 框架的强制对象和框架的使用. ...

  3. log4j学习(二) 高并发logback

    logback中常用的appender有ch.qos.logback.core.ConsoleAppender和ch.qos.logback.core.rolling.RollingFileAppen ...

  4. java实现数字转中文大写

    package cn.aikang.ChineseC; import java.util.Scanner; /** * @Description: TODO(这里用一句话描述这个类的作用) * @Au ...

  5. js只能输入数字和小数点

    1.文本框只能输入数字代码(小数点也不能输入)<input onkeyup="this.value=this.value.replace(/\D/g,'')" onafter ...

  6. 初学者学习PHP开发应该掌握的几段精华代码

    来自:http://hi.baidu.com/dckhello/item/d62b16d8994bf93449e1ddb0 经典循环例子 <HTML><HEAD><TIT ...

  7. c++11 Thread库写多线程程序

    一个简单的使用线程的Demo c++11提供了一个新的头文件<thread>提供了对线程函数的支持的声明(其他数据保护相关的声明放在其他的头文件中,暂时先从thread头文件入手吧),写一 ...

  8. (转)C++ 11 多线程--线程管理

    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...

  9. 使用<script>标签在HTML网页中插入JavaScript代码

    新朋友你在哪里(如何插入JS) 我们来看看如何写入JS代码?你只需一步操作,使用<script>标签在HTML网页中插入JavaScript代码.注意, <script>标签要 ...

  10. 简单的GridView分业,后台不需要写

    1前台代码: <asp:GridView ID="GridView1" runat="server" AllowPaging="True&quo ...