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. cv2.imwrite()指定图片存储路径

    cv2.imwrite("./data/photo_{}.jpg".format(i), photo)

  2. 3步永久性激活IntelliJ IDEA 亲测有效

    1.进到文件夹中:C:\Windows\System32\drivers\etc ,找到hosts文件,用文本编辑器打开文件,将“  0.0.0.0 account.jetbrains.com ”添加 ...

  3. jpa简单规则(转https://www.cnblogs.com/rulian/p/6434631.html)

    一.常用规则速查 1  And 并且2  Or  或3  Is,Equals 等于4  Between  两者之间5  LessThan 小于6  LessThanEqual   小于等于7  Gre ...

  4. Interesting HDU - 5785 回文树

    题意: 找出所有[i,j]为回文串[j+1,k]也为回文串的i*k乘积之和. 题解: 设sum1[i] 为正着插入,到 i 的所有回文串的起始位置的前缀和,sum2[i] 表示反正插入的前缀和 ans ...

  5. kafka 入门

    李克华 云计算高级群: 292870151 195907286 交流:Hadoop.NoSQL.分布式.lucene.solr.nutch  kafka入门:简介.使用场景.设计原理.主要配置及集群搭 ...

  6. JAVA时间工具类用法

    1.获得N天前的TIMESTAMP Calendar cl = Calendar.getInstance(); cl.add(Calendar.DAY_OF_YEAR, -7); Date date ...

  7. nodejs http ejs

    // ejs-demo.jsvar http = require('http'); var ejs = require('ejs'); var url = require('url'); // 搭建 ...

  8. 关于python merge后数据行数增加的问题

    其中一个可能的原因是 join 的 data 里面的列不唯一,也就是要匹配的表里面有些一行数据对应了被匹配表多条数据,这样出来可能会增加行数,可以再查一下被匹配表里的数据是否去重

  9. artTemplate(mark)

    一个渲染性能出众模板引擎,无论在 NodeJS 还是在浏览器中都可以运行. 特性 拥有接近 JavaScript 渲染极限的的性能 调试友好:语法.运行时错误日志精确到模板所在行:支持在模板文件上打断 ...

  10. Laravel 迁移检查表是否存在

    Schema::hasTable('TableName'); //检查表释放存在 Schema::hasColumn('tableName', 'columeName'); //检查表是否存在某个字段 ...