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. 第36讲 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景

    在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...

  2. Codeforces 1167C - News Distribution

    题目链接:http://codeforces.com/problemset/problem/1167/C 题意:大概就是分成几个小团体,给每个人用1 - n编号,当对某个人传播消息的时候,整个小团体就 ...

  3. 史上最全Redis面试题及答案。

    花了大量时间整理了这套Redis面试题 首发50题,绝无仅有,从入门到精通 从基础,高级知识点,再到集群,运维,方案- 弄明白了这些题可以说可以成为面霸了 面试官都得折服,Redis学得怎么样,都来检 ...

  4. 天道神诀---DHCP服务(下篇)

    DHCP作用域详解 subnet  定义一个作用域 netmask  定义作用域的掩码 range  允许发放的IP范围 option routers 指定网关地址 option domain-nam ...

  5. 2018湘潭大学程序设计竞赛【B】

    题目链接: https://www.nowcoder.com/acm/contest/105/B 题意: 给你一个字母矩阵,和测试组数,让你统计字符串的字符累计出现的次数,然后让你找出需要找的字符,这 ...

  6. 连接mysql并查询

    1.将mysql-connector-java-5.1.7-bin.jar放入Jmeter安装目录的bin文件夹中 2.在顶层目录<测试计划>中加载驱动 3.添加JDBC Connecti ...

  7. WriteFile

    从R3 ,到磁盘 1:kernel32  WriteFile 1) 挺惊讶的,符号好使了, 前面大概4条判断,根据句柄判断要写到什么地方,一共有4个地方可能要去, stdin   stdout   s ...

  8. 将数据写到kafka的topic

    package test05 import java.util.Propertiesimport org.apache.kafka.clients.producer.{KafkaProducer, P ...

  9. SPN扫描利用

    一.利用环境: 在内网渗透的信息收集中,机器服务探测一般都是通过端口扫描去做的,但是有些环境不允许这些操作.通过利用 SPN 扫描可快速定位开启了关键服务的机器,这样就不需要去扫对应服务的端口,有效规 ...

  10. 在vue中使用高德地图vue-amap

    1.安装 vue-amap我安装指定版本0.5.10的版本 npm i --save vue-amap@0.5.10 2.main.js中的配置 key申请地址教程:https://lbs.amap. ...