A:
经典的换根dp
拆成
维护两个求和符号里的值。
换根即可。
#include
using namespace std;
typedef long long ll;
const int M = 1e5+7;
int head[M],cnt;
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=w,head[x]=cnt;}
ll sm=0;
ll t[M];
ll a[M];// \sum {w(i,j)}
ll b[M];// \sum{w(i,j)*t[j]}
ll siz[M],sit[M];//以i为根的子树中节点的个数 ,节点权值和
int n;
void dfs(int x,int fa)
{
siz[x]=1;sit[x]=t[x];
a[x]=0;
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to,w=ee[i].val;
if(y==fa)continue;
dfs(y,x);
siz[x]+=siz[y];
sit[x]+=sit[y];
a[x]+=a[y]+siz[y]*w;
b[x]+=b[y]+sit[y]*w;
}
}
void DFS(int x,int fa)
{
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to,w=ee[i].val;
if(y==fa)continue;
a[y]=a[x]-siz[y]*w+(n-siz[y])*w;
b[y]=b[x]-sit[y]*w+(sm-sit[y])*w;
DFS(y,x);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&t[i]),sm+=t[i];
for(int i=1;i
B:
类似单调栈的思想
把数字从前往后排,加入后面的数字比前面的数字小,且后面还有与前面相同的数字。则把前面的数字剔除。
比如
5432141155
单调栈内的元素变化:
5 -- {加入5}
54 -- {加入4}
3-- {加入3,弹出5,4因为3放前面更优,且后面有4,5}
32-- {加入2}
321-- {加入1}
3214-- {加入4}
3214-- {加入1,前面有过1了,且没被弹出,说明1放前面更优}
3214-- {加入1,同上}
32145-- {加入5}
32145-- {加入5,同上}
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
int a[M];
int nm[M];
int st[M],vs[M];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i],nm[a[i]]++;
int p=0;
for(int i=1;i<=n;i++)
{
nm[a[i]]--;
if(vs[a[i]])continue;//已经在栈里
while(p&&nm[st[p]]&&st[p]>a[i])vs[st[p]]=0,p--;//后面还有数,不优解去后面
st[++p]=a[i];
vs[a[i]]=1;
}
for(int i=1;i
C:
显然最短路-1
#include
using namespace std;
typedef long long ll;
const int M = 2e5+7;
int head[M],cnt;
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
int n,m;
ll d[M];
int vs[M];
priority_queue ,vector >,greater > >q;
void dij()
{
memset(d,0x3f,sizeof(d));
memset(vs,0,sizeof(vs));
d[1]=0;
q.push({d[1],1});
while(!q.empty())
{
pair tp=q.top();q.pop();
int u=tp.second ;
if(vs[u])continue;
vs[u]=1;
for(int i=head[u];i;i=ee[i].nxt)
{
int v=ee[i].to,w=ee[i].val;
if(d[v]>d[u]+w)//1经过u再到v的距离小于 1直接到v的距离 则更新距离
d[v]=d[u]+w,q.push({d[v],v});
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
int x,y,z;
for(int i=1;i<=m;i++)
cin>>x>>y,add(x,y,1),add(y,x,1);
dij();
if(d[n]>1e9)cout<<0<
D:
直接模拟过程即可。
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int a,b;
cin>>a>>b;
ll ans=0;
while(1)
{
if(a<=b)
{
cout<
E:
直接算互不相同的串的个数。
每个字符可以去一个或不取。乘法原理。
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
const int mod=11092019;
char s[M];
ll nm[30];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>s;
int n=strlen(s);
for(int i=0;i
M:
经典dfs判联通块的变形。
我们把输入想成边,然后建出点图。
dfs时往上下左右走,斜边看是否有墙堵住
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2000+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
char t[M][M];
char s[M][M];
int vs[M][M];
int n,m;
bool f;
void dfs(int x,int y)
{
if(s[x][y]=='#')return ;
if(x<0||x>n||y<0||y>m)
{
f=true;//可以逃出迷宫
return ;
}
s[x][y]='#';
// cout<>n>>m;
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)s[i][j]='.';
for(int i=0;i>t[i];
int l=strlen(t[i]);
for(int j=0;j