noip模擬測試20
阿新 • • 發佈:2021-07-20
考試總結:這次考試,我非常真實地感覺到了自己能力的提高,具體來說,在之前的考試中,讀完題之後我只會想到暴力的思路,甚至有的題連暴力都打不出來,但是這次在考場上我已經有了自己的一些想法,有了一個深入思考的過程,自己演算,推式子也寫了幾張草稿紙,對於測試點的部分分也有了一定的把握。在改題的時候,我基本上都是研究下發的題解自己該出來的,總之,這幾次考試我的收穫很大,所有的付出都是值得的。
T1 玩具
思路:我們模擬一下操作過程,那麼很顯然,最終得到的應該是一顆樹,那麼如果我們不看 1 結點,那麼應該是一個森林,這道題是個 dp,我們設i個點的森林,有j個點在第一顆樹的概率\(dp_{i,j}=dp_{i-1,j-1}\times(j-1)\times(inv_i)+dp_{i-1,j}\times(i-j)\times(inv_i)\)
AC_Code
#include<bits/stdc++.h>
#define int long long
#define re register int
#define lc rt<<1
#define rc rt<<1|1
#define mid ((l+r)>>1)
#define re register int
#define ii inline int
#define iv inline void
using namespace std;
const int N=210;
long long n,p,ans;
int inv[N],g[N][N],f[N][N],dp[N][N];
ii read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=0;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return (f)?x:(-x);
}
#undef int
int main()
{
/*
i個點的森林,有j個點在第一顆樹的概率
dp[i][j]=dp[i-1][j-1]*(j-1)*inv[i]+dp[i-1][j]*(i-j)*inv[i];//拿出j-1個,加上拿另外的 i-j個
i個點的樹,深度不超過j的概率
f[i][j]=g[i-1][j-1]//畫圖顯然
i個點的森林,深度不超過j的概率
g[i][j]=sum[k=1 ->i] f[k][j]*g[i-k][j]*dp[i][k];
*/
#define int long long
n=read();
p=read();
inv[1]=1;
for(re i=2;i<=n;i++)
{
inv[i]=(p-(p/i))*inv[p%i]%p;
}
dp[1][1]=1;
for(re i=2;i<=n;i++)
{
for(re j=1;j<=i;j++)
{
dp[i][j]=(dp[i-1][j-1]%p*(j-1)%p*inv[i]+dp[i-1][j]%p*(i-j)%p*inv[i])%p;
}
}
for(re i=0;i<=n;i++)
{
g[0][i]=1;
f[1][i]=1;
}
for(re i=1;i<=n;i++)
{
for(re j=0;j<i;j++)
{
for(re k=1;k<=i;k++)
g[i][j]=(g[i][j]%p+f[k][j]%p*g[i-k][j]%p*dp[i][k]%p+p)%p;
f[i+1][j+1]=g[i][j];
for(re k=j+1;k<=n;k++)
f[i+1][k]=f[i+1][j+1];
}
for(re k=i;k<=n;k++)
g[i][k]=g[i][i-1];
}
for(re i=1;i<n;i++)
ans=(ans%p+i*(f[n][i]-f[n][i-1]+p)%p)%p;
printf("%lld\n",ans);
return 0;
}
T2 y
思路:顯然是一個狀壓dp,我們設 \(f_{i,j,s}\)表示當前走了 i 步,終點為 j,當前狀態為 S 是否可以達到,
那麼\(f_{i+1,to[j],s<<1|val[k]}|=f_{i,j,s}\),因為時間和空間的限制,我們直接列舉所有點轉移會 T飛,所以我們考慮列舉路徑的中點,正著作一遍dp,倒著做一遍dp,同時記錄每個點作為中點時的狀態,最後輸出即可。
注意細節:我們儲存狀態的時候一定要最後單獨開一個for迴圈,不要在計算的過程中儲存,否則直接T飛
AC_Code
#include<bits/stdc++.h>
#define re register int
#define lc rt<<1
#define rc rt<<1|1
#define mid ((l+r)>>1)
#define ii inline int
#define iv inline void
#define head heaaaddddd
#define next netyurywi
using namespace std;
const int N=1e4+10;
int n,m,d,tot;
long long ans=0;
int to[N<<1],next[N<<1],head[N],val[N<<1];
int f[12][95][1<<12], f2[12][95][1<<12];
vector<int> v1[95],v2[95];
bool vis[1<<22];
ii read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=0;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return (f)?x:(-x);
}
iv add(int x,int y,int z)
{
to[++tot]=y;
next[tot]=head[x];
head[x]=tot;
val[tot]=z;
}
int main()
{
n=read();
m=read();
d=read();
int a,b,c;
for(re i=1;i<=m;i++)
{
a=read();
b=read();
c=read();
add(a,b,c);
add(b,a,c);
}
int d1=(d>>1);
int d2=d-d1;
f[0][1][0]=1;
for(re i=0;i<d1;i++)
{
for(re j=1;j<=n;j++)
{
for(re k=head[j];k;k=next[k])
{
int p=to[k];
for(re s=0;s<(1<<i);s++)
{
f[i+1][p][s<<1|val[k]]|=f[i][j][s];
}
}
}
}
for(re i=1;i<=n;i++)
f2[0][i][0]=1;
for(re i=0;i<d2;i++)
{
for(re j=1;j<=n;j++)
{
for(re k=head[j];k;k=next[k])
{
int p=to[k];
for(re s=0;s<(1<<i);s++)
{
f2[i+1][p][s<<1|val[k]]|=f2[i][j][s];
}
}
}
}
for(re i=1;i<=n;i++)
{
for(re j = 0;j<(1 << d1);j++)
{
if(f[d1][i][j])
v1[i].push_back(j);
}
}
for(re i=1;i<=n;i++)
{
for(re j=0;j <(1<<d2);j++)
{
if(f2[d2][i][j])
v2[i].push_back(j);
}
}
for(re k=1;k<=n;k++)
{
for(re i=0;i<v1[k].size();i++)
{
for(re j=0;j<v2[k].size();j++)
{
if(vis[v1[k][i]<<(d2)|v2[k][j]])
continue;
vis[v1[k][i]<<(d2)|v2[k][j]]=1;
++ans;
}
}
}
printf("%lld\n",ans);
return 0;
}
T3 z
留坑