其实就是某种程度上的树上最长链。
#include<bits/stdc++.h>
using namespace std;
constexpr int Size=1e6+1;
typedef long long lli;
struct edge{
int v;
lli w;
int nxt;
edge():v(0),w(0),nxt(0){}
edge(int _v,lli _w,int _nxt):v(_v),w(_w),nxt(_nxt){}
}e[Size];
int n;
int head[Size];
lli ans;
lli cap[Size];
lli dfs(lli now,lli father);
void add_edge(int u,int v,lli w);
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",cap+i);
for(int i=1,u,v;i<n;i++){
lli w;
scanf("%d%d%lld",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
dfs(1,0);
printf("%lld",ans);
return 0;
}
lli dfs(lli now,lli father)
{
lli sub(0),lth(0);
for(int i=head[now];i!=0;i=e[i].nxt){
if(e[i].v==father)
continue;
lli val=dfs(e[i].v,now)-e[i].w;
if(val>sub) sub=val;
if(sub>lth) swap(sub,lth);
}
lli res=lth+sub+cap[now];
ans=max(ans,res);
return lth+cap[now];
}
void add_edge(int u,int v,lli w)
{
static int cnt;
e[++cnt]={v,w,head[u]};
head[u]=cnt;
}
设f[i][j]=n
代表数组的第i
位在前i
位的数字之和模3
等于j
时共有n
种可能的取值,循环时引入k
来状态转移即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long lli;
constexpr int Size=1e6+1,Mod=1e9+7;
int n,l,r;
lli f[Size][3];
inline lli add(lli &a,lli b){return a=(a+b)%Mod;}
int main()
{
scanf("%d%d%d",&n,&l,&r);
f[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
add(f[i][(j+k)%3],f[i-1][j]*((r-k+3)/3-(l-1-k+3)/3));
printf("%lld",f[n][0]%Mod);
}
设三元组(d,s,n)
代表能被d
整除且各位数字之和为s
的最小正整数是n
,for(0->9)
逐位枚举状态,则状态转移方程为:
\[ \left\{ \begin{align} d_i&=(d_{now}\times 10+i)\ \mathrm{mod}\ d\\ s_i&=s_{now}+i\\ n_i&=i \end{align} \right. \]
用广搜进行状态转移即可。
#include<bits/stdc++.h>
#define wrap make_pair
using namespace std;
typedef pair<int,int> pir;
struct node{
int d,s,val;
node():d(0),s(0),val(0){}
node(int _d,int _s,int _v):d(_d),s(_s),val(_v){}
}ans[501][5001];
int d,s;
queue<pir> q;
bitset<5001> vis[501];
void bfs();
void print(int nd,int ns);
int main()
{
scanf("%d%d",&d,&s);
bfs();
vis[0][s]?print(0,s):(void)printf("-1");
return 0;
}
void bfs()
{
vis[0][0]=true;
q.push(wrap(0,0));
while(!q.empty()){
int nd,ns;
tie(nd,ns)=q.front();
q.pop();
for(int i=0;i<=9;i++){
int di=(nd*10+i)%d;
int si=ns+i;
if(vis[di][si]||si>s)
continue;
vis[di][si]=true;
ans[di][si]={nd,ns,i};
q.push(wrap(di,si));
}
}
}
void print(int nd,int ns)
{
if(nd==0&&ns==0)
return;
print(ans[nd][ns].d,ans[nd][ns].s);
putchar(ans[nd][ns].val+'0');
}