20190102杂题

总结:难度<=noip,不能ak说明自己对卡常的掌控不够熟练。

A. 【18 省选 3】树的染色

不难发现因为限定了每个子树中和根同色的总权值为vi,所以可以贪心地使另一种颜色总权值最小,背包即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define inf 10000005
 4 #define N 5005
 5 int ff,fa[N],f[1005][N],g[N],p[N],q[N],v[N];
 6 vector<int>G[N];
 7 void dfs(int x)
 8 {
 9     if(G[x].size()==0){p[x]=v[x];q[x]=0;return;}
10     for(int i=0;i<=v[x];i++)f[x][i]=0;
11     for(int i=0;i<G[x].size();i++)
12     {
13         int y=G[x][i];dfs(y);
14         for(int j=0;j<=v[x];j++)g[j]=inf;
15         for(int j=0;j<=v[x];j++)if(j>=p[y])g[j]=min(g[j],f[x][j-p[y]]+q[y]);
16         for(int j=0;j<=v[x];j++)if(j>=q[y])g[j]=min(g[j],f[x][j-q[y]]+p[y]);
17         for(int j=0;j<=v[x];j++)f[x][j]=g[j];
18     }
19     p[x]=v[x];q[x]=inf;
20     for(int i=0;i<=v[x];i++)q[x]=min(q[x],f[x][i]);
21     if(q[x]>=inf)ff=0;
22 }
23 int main()
24 {
25     int T;scanf("%d",&T);
26     while(T--)
27     {
28         int n;scanf("%d",&n);
29         for(int i=1;i<=n;i++)G[i].clear();
30         for(int i=2;i<=n;i++)scanf("%d",&fa[i]),G[fa[i]].push_back(i);
31         for(int i=1;i<=n;i++)scanf("%d",&v[i]);
32         ff=1;dfs(1);
33         if(ff)puts("POSSIBLE");else puts("IMPOSSIBLE");
34     }
35     return 0;
36 }
View Code

B. 【18 省选 3】树形图求和

有向图的生成树计数可以用出度矩阵-邻接矩阵去掉根所在行列的矩阵A的行列式得到,此题可以考虑先求出所有生成树个数S,每次枚举一条边权为w,去掉w对矩阵的影响求生成树个数s,贡献是(S-s)*w,

考虑如何快速计算S-s,用行列式的计算方法我们可以枚举w(u,v)所在的行u展开,S-s等于T(u,u)-T(u,v)其中T(x,y)=表示(-1)x+yM(x,y),M(x,y)是行列式去掉行x列y的余子式,相当于需要快速计算T矩阵。T的转置A'是矩阵A的伴随矩阵,可以由定理A*A'=|A|*E快速求出,只需要高斯消元实现行列式求值和矩阵求逆即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=305,M=1e5+5,mod=1e9+7;
 4 int n,m,ans,u[M],v[M],w[M],mat[N][N],t[N][N],t1[N][N],t2[N][N];
 5 int pw(int a,int b){int r=1;for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)r=1ll*r*a%mod;return r;}
 6 int det()
 7 {
 8     int d=1;
 9     for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)t[i][j]=mat[i][j];
10     for(int i=1;i<n;i++)
11     {
12         for(int j=i;j<n;j++)if(mat[j][i])
13         {
14             swap(mat[i],mat[j]);
15             if(i!=j)d=1ll*d*(mod-1)%mod;
16             break;
17         }
18         int iv=pw(mat[i][i],mod-2);
19         for(int j=i+1;j<n;j++)
20         {
21             int c=1ll*mat[j][i]*iv%mod;
22             for(int k=i;k<n;k++)mat[j][k]=(mat[j][k]-1ll*c*mat[i][k]%mod+mod)%mod;
23         }
24         d=1ll*d*mat[i][i]%mod;
25     }
26     for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)mat[i][j]=t[i][j];
27     return d;
28 }
29 void pre()
30 {
31     for(int i=1;i<n;i++)t2[i][i]=1;
32     for(int i=1;i<n;i++)for(int j=1;j<n;j++)t1[i][j]=mat[j][i];
33     for(int i=1;i<n;i++)
34     {
35         for(int j=i;j<n;j++)if(t1[j][i]){swap(t1[i],t1[j]);swap(t2[i],t2[j]);break;}
36         int iv=pw(t1[i][i],mod-2);
37         for(int j=1;j<n;j++)t1[i][j]=1ll*t1[i][j]*iv%mod,t2[i][j]=1ll*t2[i][j]*iv%mod;
38         for(int j=1;j<n;j++)if(j!=i)
39         {
40             int c=t1[j][i];
41             for(int k=1;k<n;k++)t1[j][k]=(t1[j][k]-1ll*c*t1[i][k]%mod+mod)%mod,t2[j][k]=(t2[j][k]-1ll*c*t2[i][k]%mod+mod)%mod;
42         }
43     }
44 }
45 int main()
46 {
47     scanf("%d%d",&n,&m);
48     for(int i=1;i<=m;i++)
49     {
50         scanf("%d%d%d",&u[i],&v[i],&w[i]);
51         mat[u[i]][u[i]]++;mat[u[i]][v[i]]--;
52     }
53     pre();int r=det(),ans=0;
54     for(int i=1;i<=m;i++)if(u[i]<n)
55     {
56         int x=(t2[u[i]][u[i]]-t2[u[i]][v[i]]+mod)%mod;
57         (ans+=1ll*r*x%mod*w[i]%mod)%=mod;
58     }
59     printf("%d\n",ans);
60     return 0;
61 }
View Code

C. 【18 省选 3】波波老师

注意常数:线性被卡惨案。由于字符集大小为5,所以考虑SAM的线性做法,套上单调队列即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define N 10000005
 5 #define inf 1000000007
 6 int n,cnt,lst,len[N],lk[N],ch[N][5],id[N>>1],f[N>>1],q[N>>1],dp[N>>1];
 7 char s[N>>1];bool ff[N];ll res;
 8 int extend(int c)
 9 {
10     int p=lst,np=lst=++cnt;len[np]=len[p]+1;
11     for(;p&&!ch[p][c];p=lk[p])ch[p][c]=np;
12     if(!p)lk[np]=1;
13     else
14     {
15         int q=ch[p][c],nq;
16         if(len[q]==len[p]+1)lk[np]=q;
17         else
18         {
19             nq=++cnt;len[nq]=len[p]+1;lk[nq]=lk[q];lk[q]=lk[np]=nq;
20             memcpy(ch[nq],ch[q],sizeof(ch[q]));
21             for(;p&&ch[p][c]==q;p=lk[p])ch[p][c]=nq;
22         }
23     }
24     return lst;
25 } 
26 int main()
27 {
28     scanf("%s",s);n=strlen(s);lst=cnt=1;
29     for(int i=n-1;i>=0;i--)id[i]=extend(s[i]-'a');
30     for(int i=2;i<=cnt;i++)ff[lk[i]]=1;
31     for(int i=0;i<n;i++)if(ff[id[i]])f[i]=inf;else f[i]=len[lk[id[i]]]+1;
32     for(int i=0;i<n;i++)dp[i]=inf;
33     for(int i=0,l=1,r=0;i<n;i++)
34     {
35         for(;l<=r&&f[q[r]]>f[i];r--);
36         q[++r]=i;
37         for(;l<=r&&q[l]+f[q[l]]<=i;l++);
38         dp[i]=f[q[l]];
39     }
40     for(int i=1;i<n;i++)dp[i]=min(dp[i],dp[i-1]+1);
41     for(int i=0;i<n;i++)res+=dp[i];
42     printf("%lld\n",res);
43     return 0;
44 }
View Code

猜你喜欢

转载自www.cnblogs.com/xyleo/p/10212096.html