10.28 考试
T1
好水啊~~~
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int N=100006; int first[N],nt[N*2],ver[N*2],e; void addbian(int u,int v) { ver[e]=v; nt[e]=first[u]; first[u]=e++; } int n,an; int fa[N],xi[N],id[N]; void dfs(int x) { xi[x]=1; int i; for(i=first[x];i!=-1;i=nt[i]) { if(ver[i]==fa[x]) continue; fa[ver[i]]=x; id[ver[i]]=(i>>1)+1; dfs(ver[i]); xi[x]+=xi[ver[i]]; } } int main(){ //freopen("T1.in","r",stdin); //freopen("div.in","r",stdin); //freopen("div.out","w",stdout); rint i; mem(first,-1); read(n); int tin1,tin2; for(i=1;i<n;++i) { read(tin1); read(tin2); addbian(tin1,tin2); addbian(tin2,tin1); } dfs(1); an=-1; for(i=1;i<=n;++i) if(id[i]&&xi[i]*2==n) an=id[i]; cout<<an; fclose(stdin); fclose(stdout); }
T2
题解释哈夫曼树,然而我并不是这样想的...
可以考虑在01trie上行走
那么它一定是在每一个深度都用完了,在到下一层
可以脑补一下...
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int N=10000006; const int mod=1000000007; ll qpow(ll a,int ci) { ll ans=1; while(ci) { if(ci&1) ans=ans*a%mod; a=a*a%mod; ci>>=1; } return ans; } int n; ll jie[N],jieni[N]; void chu() { int i; jie[0]=1; for(i=1;i<N;++i) jie[i]=jie[i-1]*i%mod; jieni[N-1]=qpow(jie[N-1],mod-2)%mod; for(i=N-2;i>=1;--i) jieni[i]=jieni[i+1]*(i+1)%mod; jieni[0]=1; } ll C(int n,int m) { if(n<0||m<0||n<m) return 0; return jie[n]*jieni[m]%mod*jieni[n-m]%mod; } int main(){ //freopen("str.in","r",stdin); //freopen("str.out","w",stdout); chu(); read(n); int k=0; while((1<<k)<=n) ++k; --k; printf("%lld",C((1<<k),(n-(1<<k)))%mod*jie[n]%mod ); fclose(stdin); fclose(stdout); }
T3
(1)
你可以大暴搜
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int N=5006; const int mod=1000000007; int n,K; int ans; void dfs(int order,int now,int mn,int mx) { if(mx-mn>K) return ; if(order==n+1) { ++ans; return ; } dfs(order+1,now+1,mn,max(mx,now+1)); dfs(order+1,now+2,mn,max(mx,now+2)); dfs(order+1,now-1,min(mn,now-1),mx); } int main(){ //freopen("T3.in","r",stdin); read(n); read(K); dfs(1,0,0,0); cout<<ans; }
(2)
$O(nK^3)$的dp
$f_{i,j,k,v}$ 表示当前走到了第i个位置,最大值是j,最小值是k,当前的权值是v的方案数
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int N=5006; const int mod=1000000007; const int BAO=78; int n,K; ll f[2][BAO*3][BAO][BAO*2]; ll dp() { rint i,j,k,p; int now=1,mn=BAO-n,mx=n+n+BAO,nx,tmx,tt; //printf("mn=%d mx=%d\n",mn,mx); mem(f,0); f[0][BAO][BAO][0]=1; for(i=0;i<n;++i) { now^=1; nx=now^1; mem(f[nx],0); for(j=mn;j<=mx;++j) for(k=BAO-i;k<=j;++k) for(p=max(j,BAO);p<=mx;++p) if(f[now][j][k][p-BAO]) { //printf("i=%d\n",i); tmx=p-BAO; tt=f[now][j][k][tmx]; f[nx][j+1][k][max(tmx,j+1-BAO)]+=tt; f[nx][j+1][k][max(tmx,j+1-BAO)]%=mod; f[nx][j+2][k][max(tmx,j+2-BAO)]+=tt; f[nx][j+2][k][max(tmx,j+2-BAO)]%=mod; f[nx][j-1][min(j-1,k)][tmx]+=tt; f[nx][j-1][min(j-1,k)][tmx]%=mod; } } ll ans=0; for(i=mn;i<=mx;++i) for(j=mn;j<=BAO;++j) { tt=min(j+K,mx); for(k=j;k<=tt;++k) ans=(ans+f[nx][i][j][k-BAO])%mod; } return ans; } int main(){ freopen("T3.in","r",stdin); read(n); read(K); printf("%lld",dp()); }
(3)
$O(nK^2)$ 的dp
$f_{i,j,k}$ 表示当前走到了第i个位置,最大值和最小值的差值是j,当前值比最小值大k的方案数
特别的,差值j是当前走的路线到过了最大值和最小值才行,所以不会重复
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int mod=1000000007; int n,K; ll f[2][306][306]; ll dp() { int i,j,k,tt,now=1,nx,nj,nk; ll ans=0; f[0][0][0]=1; for(i=0;i<n;++i) { now^=1; nx=now^1; mem(f[nx],0); for(j=0;j<=2*i&&j<=K;++j) for(k=0;k<=j;++k) if(f[now][j][k]) { nk=k+1; nj=j; if(nj<nk) nj=nk; if(nj<=K) f[nx][nj][nk]=(f[nx][nj][nk]+f[now][j][k])%mod; nk=k+2; nj=j; if(nj<nk) nj=nk; if(nj<=K) f[nx][nj][nk]=(f[nx][nj][nk]+f[now][j][k])%mod; nk=k-1; nj=j; if(nk<0) nj=nj-nk,nk=0; if(nj<=K) f[nx][nj][nk]=(f[nx][nj][nk]+f[now][j][k])%mod; } } for(i=0;i<=K;++i) for(j=0;j<=i;++j) ans=(ans+f[nx][i][j])%mod; return ans%mod; } int main(){ read(n); read(K); printf("%lld",dp()); }
(4)
$O(nK)$ 的dp
我们考虑在一个n*K大小的网格里从最左边往右走
枚举起点在最左边的位置,就相当于枚举最小值
$f_{i,j,k}$ 表示当前走到了第i个位置,当前的权值是j,到没到过0(也就是最小值)的方案数
这样开第三维也可以保证不重复
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int mod=1000000007; int n,K; ll f[2][5006][2]; ll dp() { int i,j,k,tt,now=1,nx; ll ans=0; f[0][0][1]=1; for(i=1;i<=K;++i) f[0][i][0]=1; for(i=0;i<n;++i) { now^=1; nx=now^1; mem(f[nx],0); for(j=0;j<=K;++j) { tt=j+1; if(tt<=K) f[nx][tt][0]=(f[nx][tt][0]+f[now][j][0])%mod,f[nx][tt][1]=(f[nx][tt][1]+f[now][j][1])%mod; tt=j+2; if(tt<=K) f[nx][tt][0]=(f[nx][tt][0]+f[now][j][0])%mod,f[nx][tt][1]=(f[nx][tt][1]+f[now][j][1])%mod; tt=j-1; if(tt>0) f[nx][tt][0]=(f[nx][tt][0]+f[now][j][0])%mod,f[nx][tt][1]=(f[nx][tt][1]+f[now][j][1])%mod; else if(tt==0) f[nx][tt][1]=(f[nx][tt][1]+f[now][j][0]+f[now][j][1])%mod; } } for(i=0;i<=K;++i) ans=(ans+f[nx][i][1])%mod; return ans%mod; } int main(){ read(n); read(K); printf("%lld",dp()); }