A. 膜拜华哥。。。。简直神仙 dp....
这道题dp 思路解决, dp [ n ] [ i ] [ j ] 代表 n 长度排列, 以第 i 号音符作为开头, j 号音符作为结尾
那么有
dp [ n ] [ i ] [ j ] = ( 1 <= k <= 49 ) 同时还要保证 k, i, j 这个排列是合法的,
开个三维 vis 记录非法排列就好了,最后结果就是
( 1<= ( i , j ) <=n)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
#define ll long long int
const ll mod = 1e9+7;
ll dp[505][55][55],vis[55][55][55];
int main()
{
ll n,q; cin>>n>>q;
for(int i=1;i<=q;i++)
{
ll a,b,c; cin>>a>>b>>c;
vis[a][b][c] = 1; vis[a][c][b] = 1;
vis[b][a][c] = 1; vis[b][c][a] = 1;
vis[c][a][b] = 1; vis[c][b][a] = 1;
}
for(int i=1;i<=49;i++)
for(int j=1;j<=49;j++)
dp[2][i][j]=1;
for(int i=2;i<=n;i++)
{
for(int a=1;a<=49;a++)
for(int b=1;b<=49;b++)
for(int c=1;c<=49;c++)
if(vis[a][b][c] == 0)
{
dp[i+1][b][c] = (dp[i+1][b][c] + dp[i][a][b])%mod;
}
}
ll sum = 0;
for(int i=1;i<=49;i++)
for(int j=1;j<=49;j++)
sum=(sum+dp[n][i][j])%mod;
cout<<sum<<endl;
return 0;
}
C. 把题干改成人话就是如何在走过每一条最多2次的情况下遍历整棵树
那么我们直接求 带权树直径,直径只走一次,其他走两次
总长度减去一条直径就完事了。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=2000005;
long long n,m,t,p,ans,sum;
struct edge{int to,nxt,w;}ed[N];
long long d[N],head[N];
void add(long long x,long long y,long long z)
{
ed[++t].nxt=head[x];head[x]=t;
ed[t].to=y; ed[t].w=z;
}
void dfs(long long x,long long father)
{
if(ans<d[x]){ ans=d[x];p=x; }
for(int i=head[x];i;i=ed[i].nxt)
{
int t = ed[i].to;
if(t==father) continue;
d[t]=d[x]+ed[i].w;
dfs(t,x);
}
}
void dfs1(long long x)
{
ans=0; d[x]=0;
dfs(x,0);
}
int main()
{
long long x,y,z;
scanf("%lld",&m);
for(int i=1;i<m;++i)
{
scanf("%lld%lld%lld",&x,&y,&z);
sum+=z;
add(x,y,z); add(y,x,z);
}
dfs1(1); dfs1(p);
printf("%lld",sum*2-ans);
return 0;
}