T1:
这不是树形背包水题吗?只是数据范围略大,注意常数。
(话说即使时间咕成NOIP,也不能放NOIP题啊)
代码:
1 #pragma GCC optimize("Ofast","no-stack-protector") 2 //#pragma GCC target("avx2") 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cctype> 7 typedef long long int lli; 8 const int maxn=4e3+1e2; 9 10 int lson[maxn],rson[maxn],c[maxn],siz[maxn]; 11 lli f[maxn][maxn]; 12 bool vis[maxn]; 13 14 inline void dfs(int pos) { 15 if( !lson[pos] && !rson[pos] ) { // a leaf node . 16 f[pos][0] = 0 , f[pos][1] = c[pos] , siz[pos] = 1; 17 return; 18 } 19 dfs(lson[pos]) , dfs(rson[pos]) , memset(f[pos],0x3f,(siz[lson[pos]]+siz[rson[pos]]+1)<<3); 20 for(int i=0;i<=siz[lson[pos]];i++) for(int j=0;j<=siz[rson[pos]];j++) f[pos][i+j] = std::min( f[pos][i+j] , f[lson[pos]][i] + f[rson[pos]][j] + (lli) ( i ^ j ) * c[pos] ); 21 siz[pos] = siz[lson[pos]] + siz[rson[pos]]; 22 } 23 24 inline int getint() { 25 int ret = 0 , ch; 26 while( !isdigit(ch=getchar()) ); 27 do ret = ret * 10 + ch - '0'; while( isdigit(ch=getchar()) ); 28 return ret; 29 } 30 31 int main() { 32 static int t,n,root; 33 t = getint(); 34 while(t--) { 35 n = getint() , memset(vis,0,sizeof(vis)); 36 for(int i=1;i<=n;i++) vis[lson[i] = getint()] = 1 , vis[rson[i] = getint()] = 1; 37 for(int i=1;i<=n;i++) c[i] = getint(); 38 for(int i=1;i<=n;i++) if( !vis[i] ) root = i; 39 dfs(root); 40 for(int i=1;i<=siz[root];i++) printf("%lld%c",f[root][i],i!=siz[root]?' ':' '); 41 } 42 return 0; 43 }
T2:
组合数学神题!考虑第一种用多少个,则答案就是C(n,i)*C(m,t-i)*C(t,i)。
好的,我会lucas定理,我能写暴力!(阻止我AK的题都不是好题.jpg)
(然而暴力的后15分由于n太大数据组数太多,根本没有实装,于是只有5分QAQ)
正解考虑lucas定理,显然我们在lucas定理的每一位都不能进位,同时n和m在每一位选择的值都不能超过t(否则组合数为0)。
所以我们令f[i][j]表示考虑最大的i层,第一种选择的数mod p=j的方案数。
转移的话,首先凑出每层自己的方案,如果n在这层的数值为n1,m为m1,t为t1,在这层选择第一种的数量为i,则g[level][i%p] += C(n1,i) * C(m1,t1-i) * C(t1,i)。(这里的g为只考虑一层的方案数)
然后考虑层与层间的结合,显然转移为f[level][(i*mod+j)%p] += f[level-1][i] * g[level][j]。变换一下下标显然是个卷积,FFT优化即可。
(怎么FFT?其实随便找一个大于mod*p的数作为模数,然后做NTT即可。当然如果你非得long double大力FFT也没人管你,能AC就好)
考场5分代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cctype> 6 typedef long long int lli; 7 using namespace std; 8 const int maxe=1e3+1e2; 9 10 lli fac[maxe],inv[maxe]; 11 bool vis[maxe]; 12 int mod,p; 13 14 inline lli lucas(lli n,lli m) { 15 if( n < m ) return 0; 16 if( n < mod && m < mod ) return fac[n] * inv[m] * inv[n-m] % mod; 17 return lucas(n/mod,m/mod) * lucas(n%mod,m%mod) % mod; 18 } 19 inline lli fastpow(lli base,int tim) { 20 lli ret = 1; 21 while(tim) { 22 if( tim & 1 ) ret = ret * base % mod; 23 if( tim >>= 1 ) base = base * base % mod; 24 } 25 return ret; 26 } 27 28 template<typename T> 29 inline T read() { 30 T ret = 0; char ch; 31 while( !isdigit(ch=getchar()) ); 32 do ret = ret * 10 + ch - '0'; while( isdigit(ch=getchar()) ); 33 return ret; 34 } 35 36 int main() { 37 static int T,siz; 38 static lli n,m,t,ans; 39 T = read<int>(); 40 while(T--) { 41 n = read<lli>() , m = read<lli>() , t = read<lli>() , mod = read<int>() , memset(vis,0,p=read<int>()) , siz = read<int>() , ans = 0; 42 while( siz-- ) vis[read<int>()] = 1; 43 *fac = 1; for(int i=1;i<mod;i++) fac[i] = fac[i-1] * i % mod; 44 inv[mod-1] = fastpow(fac[mod-1],mod-2); for(int i=mod-1;~i;i--) inv[i-1] = inv[i] * i % mod; 45 for(lli i=0;i<=n;i++) if( vis[i%p] ) ans += lucas(n,i) * lucas(m,t-i) * lucas(t,i) % mod , ans %= mod; 46 printf("%lld ",ans); 47 } 48 return 0; 49 }
正解代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cctype> 6 #define debug cout 7 typedef long long int lli; 8 using namespace std; 9 const int maxn=3e3+1e2; 10 11 namespace NTT { 12 const int mod=998244353,g=3; 13 inline int add(const int &x,const int &y) { 14 const int ret = x + y; 15 return ret >= mod ? ret - mod : ret; 16 } 17 inline int sub(const int &x,const int &y) { 18 const int ret = x - y; 19 return ret < 0 ? ret + mod : ret; 20 } 21 inline int mul(const int &x,const int &y) { 22 return (lli) x * y % mod; 23 } 24 inline void mule(int &dst,const int &x) { 25 dst = (lli) dst * x % mod; 26 } 27 inline int fastpow(int base,int tim) { 28 int ret = 1; 29 while(tim) { 30 if( tim & 1 ) mule(ret,base); 31 if( tim >>= 1 ) mule(base,base); 32 } 33 return ret; 34 } 35 inline void NTT(int* dst,int n,int tpe) { 36 for(int i=0,j=0;i<n;i++) { 37 if( i < j ) swap(dst[i],dst[j]); 38 for(int t=n>>1;(j^=t)<t;t>>=1) ; 39 } 40 for(int len=2,h=1;len<=n;len<<=1,h<<=1) { 41 int per = fastpow(g,mod/len); 42 if( !~tpe ) per = fastpow(per,mod-2); 43 for(int st=0;st<n;st+=len) { 44 int w = 1; 45 for(int pos=0;pos<h;pos++) { 46 const int u = dst[st+pos] , v = mul(dst[st+pos+h],w); 47 dst[st+pos] = add(u,v) , dst[st+pos+h] = sub(u,v) , mule(w,per); 48 } 49 } 50 } 51 if( !~tpe ) { 52 const int inv = fastpow(n,mod-2); 53 for(int i=0;i<n;i++) mule(dst[i],inv); 54 } 55 } 56 inline void mul(int* dst,int *sou,int ld,int ls) { 57 int len; for(len=1;len<=ld+ls;len<<=1) ; 58 for(int i=ld;i<len;i++) sou[i] = 0; 59 for(int i=ls;i<len;i++) dst[i] = 0; 60 NTT(dst,len,1) , NTT(sou,len,1); 61 for(int i=0;i<len;i++) mule(dst[i],sou[i]); 62 NTT(dst,len,-1); 63 } 64 } 65 66 bool vis[maxn]; 67 int fac[maxn],inv[maxn],f[2][maxn]; 68 lli n,m,t; 69 int mod,p; // mod is mod of lucas and mod of answer . 70 71 inline int c(int n,int m) { 72 if( n < m ) return 0; 73 return fac[n] * inv[m] * inv[n-m] % mod; 74 } 75 inline void trans(int* dst,int* sou) { 76 static int tp[maxn]; memset(tp,0,sizeof(tp)); 77 for(int i=0;i<p;i++) tp[i*mod%p] += sou[i]; 78 for(int i=0;i<p;i++) tp[i] %= mod; 79 NTT::mul(dst,tp,p,p); 80 for(int i=p;i<p<<1;i++) dst[i%p] += dst[i]; 81 for(int i=0;i<p;i++) dst[i] %= mod; 82 } 83 inline void initseq(int* dst,int bitn,int bitm,int bitt) { 84 for(int i=0;i<p;i++) dst[i] = 0; 85 for(int i=0;i<=bitn&&i<=bitt;i++) { 86 dst[i%p] += c(bitn,i) * c(bitm,bitt-i) * c(bitt,i) % mod; 87 } 88 for(int i=0;i<p;i++) dst[i] %= mod; 89 } 90 91 inline int fastpow(int base,int tim) { 92 int ret = 1; 93 while(tim) { 94 if( tim & 1 ) ret = ret * base % mod; 95 if( tim >>= 1 ) base = base * base % mod; 96 } 97 return ret; 98 } 99 inline void init() { 100 memset(f,0,sizeof(f)); 101 *fac = 1; for(int i=1;i<mod;i++) fac[i] = fac[i-1] * i % mod; 102 inv[mod-1] = fastpow(fac[mod-1],mod-2); for(int i=mod-1;i;i--) inv[i-1] = inv[i] * i % mod; 103 } 104 inline void getbit(int* dst,int &len,lli x) { 105 memset(dst,0,280) , len = 0; 106 while(x) dst[++len] = x % mod , x /= mod; 107 } 108 109 template<typename T> 110 inline T read() { 111 T ret = 0; char ch; 112 while( !isdigit(ch=getchar()) ) ; 113 do ret = ret * 10 + ch - '0'; while( isdigit(ch=getchar()) ); 114 return ret; 115 } 116 117 int bitn[70],bitm[70],bitt[70],tn,tm,tt; 118 119 int main() { 120 static int T,siz,cur,ans; 121 T = read<int>(); 122 while(T--) { 123 n = read<lli>() , m = read<lli>() , t = read<lli>() , mod = read<int>() , memset(vis,0,p=read<int>()) , siz = read<int>(); 124 while(siz--) vis[read<int>()] = 1; 125 init() , ans = 0 , getbit(bitn,tn,n) , getbit(bitm,tm,m) , getbit(bitt,tt,t); 126 initseq(f[cur=0],bitn[tt],bitm[tt],bitt[tt]); 127 for(int i=tt-1;i;i--) cur ^= 1 , initseq(f[cur],bitn[i],bitm[i],bitt[i]) , trans(f[cur],f[cur^1]); 128 for(int i=0;i<p;i++) if( vis[i] ) ans += f[cur][i]; 129 printf("%d ",ans%mod); 130 } 131 return 0; 132 }
T3:
考虑点分治,那么每个点最优解的路径只有两种:过当前分治重心的和不过分治重心的。
对于不过分治重心的,我们递归处理,考虑过分治重心的,显然只有每个点的最优路径才会更新答案。
好,我们到trie树中查出最大xor和取得最大xor时这个点对应的点,然后到原树上给这条链打上max标记即可。
注意这个标记可以用树链剖分+线段树实现,然而会多一个log。考虑我们只用查询一次,用ST表打标记就好啦。
另外,每个点的最优决策可能在这个点子树的前面也可能在后面,而这个点取最优解的时候对应的不一定是另一个点的最优解。
所以,需要在点分治的时候正反做两遍。否则大概会WA。
代码:
1 #pragma GCC optimize("Ofast","no-stack-protector") 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<utility> 6 #include<cctype> 7 #include<vector> 8 #define debug cout 9 using namespace std; 10 const int maxn=1e5+1e2,maxe=5e6+1e2,maxl=20; 11 const int inf=0x3f3f3f3f; 12 13 int ans[maxn],n; 14 namespace Tree { 15 int s[maxn],t[maxn<<1],nxt[maxn<<1]; 16 int dep[maxn],lazy[maxn][maxl],anc[maxn][maxl]; 17 inline void coredge(int from,int to) { 18 static int cnt; 19 t[++cnt] = to , nxt[cnt] = s[from] , s[from] = cnt; 20 } 21 inline void addedge(int a,int b) { 22 coredge(a,b) , coredge(b,a); 23 } 24 inline void pre(int pos) { 25 for(int at=s[pos];at;at=nxt[at]) if( t[at] != *anc[pos] ) dep[t[at]] = dep[*anc[t[at]]=pos] + 1 , pre(t[at]); 26 } 27 inline void init() { 28 for(int j=1;j<maxl;j++) for(int i=1;i<=n;i++) anc[i][j] = anc[anc[i][j-1]][j-1]; 29 } 30 inline int lca(int x,int y) { 31 if( dep[x] < dep[y] ) swap(x,y); 32 for(int i=maxl-1;~i;i--) if( dep[x] - ( 1 << i ) >= dep[y] ) x = anc[x][i]; 33 if( x == y ) return x; 34 for(int i=maxl-1;~i;i--) if( anc[x][i] != anc[y][i] ) x = anc[x][i] , y = anc[y][i]; 35 return *anc[x]; 36 } 37 inline int getlen(int s,int f) { 38 return dep[s] - dep[f] + 1; 39 } 40 inline void markchain(int x,int dep,int v) { // mark dep points . 41 for(int i=maxl-1;~i;i--) if( dep - ( 1 << i ) >= 0 ) { 42 lazy[x][i] = max( lazy[x][i] , v ) , dep -= 1 << i , x = anc[x][i]; 43 } 44 } 45 inline void pushall() { 46 for(int j=maxl-1;j;j--) for(int i=1;i<=n;i++) { 47 lazy[i][j-1] = max( lazy[i][j-1] , lazy[i][j] ) , 48 lazy[anc[i][j-1]][j-1] = max( lazy[anc[i][j-1]][j-1] , lazy[i][j] ); 49 } 50 for(int i=1;i<=n;i++) ans[i] = *lazy[i]; 51 } 52 } 53 54 typedef pair<int,int> pii; 55 inline pii mp(const int &x,const int &y) { return (pii){x,y}; } 56 57 int root; 58 struct Trie { // dep from 30 downto -1 becaus 2^30 > 1e9 so it can't have bit 2^31 . 59 int ch[maxe][2],id[maxe],cnt; // identity of leaf node . 60 inline void insert(int &pos,int dep,const int &val,const int &iid) { 61 if( !pos ) pos = ++cnt; 62 if( !~dep ) return void(id[pos] = iid); 63 int bit = ( val >> dep ) & 1; insert(ch[pos][bit],dep-1,val,iid); 64 } 65 inline pii query(int pos,int dep,const int &val) { 66 if( !~dep ) return mp(0,id[pos]); 67 int bit = ( ( val >> dep ) & 1 ) ^ 1; 68 if( ch[pos][bit] ) { 69 pii qs = query(ch[pos][bit],dep-1,val); 70 return mp(qs.first|(1<<dep),qs.second); 71 } else return query(ch[pos][bit^1],dep-1,val); // pos must have at least one son . 72 } 73 inline void reset() { 74 ++cnt , memset(ch,0,sizeof(ch[0])*cnt) , memset(id,0,sizeof(id[0])*cnt) , cnt = 0 , root = 0; 75 } 76 }trie; 77 78 namespace TDAC { 79 int s[maxn],t[maxn<<1],nxt[maxn<<1],l[maxn<<1]; 80 int siz[maxn],mxs[maxn],ban[maxn],vs[maxn],is[maxn],cnt; 81 inline void coredge(int from,int to,int len) { 82 static int cnt; 83 t[++cnt] = to , l[cnt] = len , nxt[cnt] = s[from] , s[from] = cnt; 84 } 85 inline void addedge(int a,int b,int l) { 86 coredge(a,b,l) , coredge(b,a,l); 87 } 88 inline void getroot(int pos,int fa,const int &fs,int &rt) { 89 siz[pos] = 1 , mxs[pos] = 0; 90 for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa && !ban[t[at]] ) getroot(t[at],pos,fs,rt) , siz[pos] += siz[t[at]] , mxs[pos] = max( mxs[pos] , siz[t[at]] ); 91 if( ( mxs[pos] = max( mxs[pos] , fs - siz[pos]) ) <= mxs[rt] ) rt = pos; // *mxs == inf . 92 } 93 inline void dfs(int pos,int fa,int su) { 94 vs[++cnt] = su , is[cnt] = pos; 95 for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa && !ban[t[at]] ) dfs(t[at],pos,su^l[at]); 96 } 97 inline void solve(int pos,int fs) { 98 if( fs == 1 ) return; 99 int rt = 0; *mxs = inf , getroot(pos,-1,fs,rt) , ban[rt] = 1; 100 101 static vector<int> sons,lens; sons.clear() , lens.clear(); 102 for(int at=s[rt];at;at=nxt[at]) if( !ban[t[at]] ) sons.push_back(t[at]) , lens.push_back(l[at]); 103 104 trie.reset() , trie.insert(root,30,0,rt); 105 for(unsigned i=0;i<sons.size();i++) { 106 cnt = 0 , dfs(sons[i],rt,lens[i]); 107 for(int i=1;i<=cnt;i++) { 108 pii qry = trie.query(root,30,vs[i]); int lca = Tree::lca(is[i],qry.second); 109 Tree::markchain(is[i],Tree::getlen(is[i],lca),qry.first) , Tree::markchain(qry.second,Tree::getlen(qry.second,lca),qry.first); 110 } 111 for(int i=1;i<=cnt;i++) trie.insert(root,30,vs[i],is[i]); 112 } 113 114 reverse(sons.begin(),sons.end()) , reverse(lens.begin(),lens.end()); 115 116 trie.reset() , trie.insert(root,30,0,rt); 117 for(unsigned i=0;i<sons.size();i++) { 118 cnt = 0 , dfs(sons[i],rt,lens[i]); 119 for(int i=1;i<=cnt;i++) { 120 pii qry = trie.query(root,30,vs[i]); int lca = Tree::lca(is[i],qry.second); 121 Tree::markchain(is[i],Tree::getlen(is[i],lca),qry.first) , Tree::markchain(qry.second,Tree::getlen(qry.second,lca),qry.first); 122 } 123 for(int i=1;i<=cnt;i++) trie.insert(root,30,vs[i],is[i]); 124 } 125 126 for(int at=s[rt];at;at=nxt[at]) if( !ban[t[at]] ) solve(t[at],siz[t[at]]<siz[rt]?siz[t[at]]:fs-siz[rt]); 127 } 128 } 129 130 namespace IO { 131 inline char nextchar() { 132 static const int BS = 1 << 21; 133 static char buf[BS],*st,*ed; 134 if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin); 135 return st == ed ? -1 : *st++; 136 } 137 inline int getint() { 138 int ret = 0; char ch; 139 while( !isdigit(ch=nextchar()) ) ; 140 do ret = ret * 10 + ch - '0'; while( isdigit(ch=nextchar()) ); 141 return ret; 142 } 143 } 144 using IO::getint; 145 146 int main() { 147 n = getint(); 148 for(int i=1,a,b,l;i<n;i++) a = getint() , b = getint() , l = getint() , Tree::addedge(a,b) , TDAC::addedge(a,b,l); 149 Tree::pre(1) , Tree::init() , TDAC::solve(1,n) , Tree::pushall(); 150 for(int i=1;i<=n;i++) printf("%d ",ans[i]); 151 return 0; 152 }
这次虽然又是rank1了,不过和第二只差5分......
被NOIP题卡了,不开心。