洛谷P1850
两个序列 c c c, d d d,你需依次走过这 n n n个点,如果申请,则有 p p pi 的机会将 c c ci 换成 d d di,但你只能申请 m m m次,求走过这 n n n个点的路径总和的期望最小值。
期望 D P DP DP
f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1]表示走过前 i i i个点,当前点是否申请的期望
f [ i ] [ j ] [ 0 ] = m i n ( f [ i − 1 ] [ j ] [ 0 ] + d i s [ c [ i − 1 ] ] [ c [ i ] ] , f [ i − 1 ] [ j ] [ 1 ] + p [ i − 1 ] ∗ d i s [ d [ i − 1 ] ] [ c [ i ] ] + ( 1 − p [ i − 1 ] ) ∗ d i s [ c [ i − 1 ] ] [ c [ i ] ] ; f[i][j][0]=min(f[i-1][j][0]+dis[c[i-1]][c[i]],f[i-1][j][1]+p[i-1]*dis[d[i-1]][c[i]]+(1-p[i-1])*dis[c[i-1]][c[i]]; f[i][j][0]=min(f[i−1][j][0]+dis[c[i−1]][c[i]],f[i−1][j][1]+p[i−1]∗dis[d[i−1]][c[i]]+(1−p[i−1])∗dis[c[i−1]][c[i]];
f [ i ] [ j ] [ 1 ] = m i n ( f [ i − 1 ] [ j − 1 ] [ 0 ] + d i s [ c [ i − 1 ] ] [ c [ i ] ] ∗ ( 1 − p [ i ] ) + d i s [ c [ i − 1 ] ] [ d [ i ] ] ∗ p [ i ] , f [ i − 1 ] [ j − 1 ] [ 1 ] + d i s [ c [ i − 1 ] [ c [ i ] ] ∗ ( 1 − p [ i − 1 ] ) ∗ ( 1 − p [ i ] ) + d i s [ c [ i − 1 ] ] [ d [ i ] ] ∗ ( 1 − p [ i − 1 ] ) ∗ p [ i ] + d i s [ d [ i − 1 ] ] [ c [ i ] ∗ p [ i − 1 ] ∗ ( 1 − p [ i ] ) + d i s [ d [ i − 1 ] ] [ d [ i ] ] ∗ p [ i − 1 ] ∗ p [ i ] ; f[i][j][1]=min(f[i-1][j-1][0]+dis[c[i-1]][c[i]]*(1-p[i])+dis[c[i-1]][d[i]]*p[i],f[i-1][j-1][1]+dis[c[i-1][c[i]]*(1-p[i-1])*(1-p[i])+dis[c[i-1]][d[i]]*(1-p[i-1])*p[i]+dis[d[i-1]][c[i]*p[i-1]*(1-p[i])+dis[d[i-1]][d[i]]*p[i-1]*p[i]; f[i][j][1]=min(f[i−1][j−1][0]+dis[c[i−1]][c[i]]∗(1−p[i])+dis[c[i−1]][d[i]]∗p[i],f[i−1][j−1][1]+dis[c[i−1][c[i]]∗(1−p[i−1])∗(1−p[i])+dis[c[i−1]][d[i]]∗(1−p[i−1])∗p[i]+dis[d[i−1]][c[i]∗p[i−1]∗(1−p[i])+dis[d[i−1]][d[i]]∗p[i−1]∗p[i];
如果写成
f [ i ] [ j ] [ 1 ] = m i n ( f [ i − 1 ] [ j − 1 ] [ 1 ] + p [ i − 1 ] ∗ d i s [ d [ i − 1 ] ] [ d [ i ] ] + ( 1 − p [ i − 1 ] ) ∗ d i s [ c [ i − 1 ] ] [ d [ i ] ] , f [ i − 1 ] [ j − 1 ] [ 0 ] + d i s [ c [ i − 1 ] ] [ d [ i ] ] ) ∗ p [ i ] + ( 1 − p [ i ] ) ∗ m i n ( f [ i − 1 ] [ j − 1 ] [ 0 ] + d i s [ c [ i − 1 ] ] [ c [ i ] ] , f [ i − 1 ] [ j − 1 ] [ 1 ] + p [ i − 1 ] ∗ d i s [ d [ i − 1 ] ] [ c [ i ] ] + ( 1 − p [ i − 1 ] ) ∗ d i s [ c [ i − 1 ] ] [ c [ i ] ] ) ; f[i][j][1]=min(f[i-1][j-1][1]+p[i-1]*dis[d[i-1]][d[i]]+(1-p[i-1])*dis[c[i-1]][d[i]],f[i-1][j-1][0]+dis[c[i-1]][d[i]])*p[i]+(1-p[i])*min(f[i-1][j-1][0]+dis[c[i-1]][c[i]],f[i-1][j-1][1]+p[i-1]*dis[d[i-1]][c[i]]+(1-p[i-1])*dis[c[i-1]][c[i]]); f[i][j][1]=min(f[i−1][j−1][1]+p[i−1]∗dis[d[i−1]][d[i]]+(1−p[i−1])∗dis[c[i−1]][d[i]],f[i−1][j−1][0]+dis[c[i−1]][d[i]])∗p[i]+(1−p[i])∗min(f[i−1][j−1][0]+dis[c[i−1]][c[i]],f[i−1][j−1][1]+p[i−1]∗dis[d[i−1]][c[i]]+(1−p[i−1])∗dis[c[i−1]][c[i]]);
会精度丢失,WA3个点
终于会期望了,不过对于 d o u b l e double double精度丢失很懵逼
f f f数组一定要清零,以免用到一些不存在的状态!!!
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(x=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int V=304,N=2004,inf=0x3f3f3f3f;
int n,m,v,e,dis[V][V],c[N],d[N];
double p[N],f[N][N][2],ans=inf;
int main(){
n=read();m=read();v=read();e=read();
for(int i=1;i<=n;i++)c[i]=read();
for(int i=1;i<=n;i++)d[i]=read();
for(int i=1;i<=n;i++)scanf("%lf",&p[i]);
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=v;i++)dis[i][i]=0;
for(int i=1,u,x,w;i<=e;i++){
u=read();x=read();w=read();
dis[u][x]=dis[x][u]=min(w,dis[u][x]);
}
for(int k=1;k<=v;k++)
for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
f[i][j][0]=f[i][j][1]=inf;
f[1][0][0]=f[1][1][1]=0;
for(int i=2;i<=n;i++){
f[i][0][0]=f[i-1][0][0]+dis[c[i-1]][c[i]];
for(int j=1;j<=i&&j<=m;j++){
f[i][j][0]=min(f[i-1][j][1]+p[i-1]*dis[d[i-1]][c[i]]+(1-p[i-1])*dis[c[i-1]][c[i]],f[i-1][j][0]+dis[c[i-1]][c[i]]);
f[i][j][1]=min(f[i-1][j-1][1]+p[i]*p[i-1]*dis[d[i-1]][d[i]]+p[i]*(1-p[i-1])*dis[c[i-1]][d[i]]+(1-p[i])*p[i-1]*dis[d[i-1]][c[i]]+(1-p[i])*(1-p[i-1])*dis[c[i-1]][c[i]],f[i-1][j-1][0]+p[i]*dis[c[i-1]][d[i]]+(1-p[i])*dis[c[i-1]][c[i]]);
//精度
}
}
for(int i=0;i<=m;i++)
ans=min(ans,min(f[n][i][0],i>0?f[n][i][1]:inf));
printf("%.2lf",ans);
return (0-0);
}
洛谷P3391
区间翻转,输出最终区间
s p l a y splay splay
下标建树,对于翻转的区间,通过 s p l a y splay splay形成一棵子树,打翻转标记, p u s h d o w n pushdown pushdown时交换左右儿子,只有在 f i n d find find时才 p u s h d o w n pushdown pushdown?
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e5+4;
int n,m,fa[N],ch[N][2],siz[N],rev[N],rt;
inline void pushup(int x){
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
inline bool getson(int p){
return ch[fa[p]][1]==p;
}
inline void pushdown(int p){
if(!rev[p])return;
swap(ch[p][0],ch[p][1]);
rev[ch[p][0]]^=1;rev[ch[p][1]]^=1;
rev[p]^=1;
}
inline void rotate(int p){
int f=fa[p],g=fa[f],r=getson(p);
if(f!=rt)ch[g][getson(f)]=p;fa[p]=g;
ch[f][r]=ch[p][r^1];if(ch[f][r])fa[ch[f][r]]=f;
ch[p][r^1]=f;fa[f]=p;
pushup(f);pushup(p);
}
inline void splay(int p,int k){
for(;fa[p]!=k;rotate(p)){
if(fa[fa[p]]!=k)rotate(getson(p)==getson(fa[p])?fa[p]:p);
}
if(!k)rt=p;
}
inline void build(int l,int r,int f){
if(l>r)return;
int mid=(l+r)>>1;
if(mid<f)ch[f][0]=mid;
else ch[f][1]=mid;
fa[mid]=f;siz[mid]=1;//
if(l==r)return;
build(l,mid-1,mid);build(mid+1,r,mid);
pushup(mid);
}
inline int find(int x,int k){
pushdown(x);
int s=siz[ch[x][0]];
if(k==s+1)return x;
if(k<=s)return find(ch[x][0],k);
return find(ch[x][1],k-s-1);
}
inline void rever(int l,int r){//l+1->r+1
int x=find(rt,l),y=find(rt,r+2);
splay(x,0);splay(y,x);
rev[ch[y][0]]^=1;
}
int main(){
n=read();m=read();
rt=(n+3)/2;build(1,n+2,0);//
for(int i=1,l,r;i<=m;i++){
l=read();r=read();
rever(l,r);
}
for(int i=2;i<=n+1;i++)printf("%d ",find(rt,i)-1);
return 0;
}
洛谷P4008
s p l a y splay splay
每次插入把根节点的右儿子的左儿子弄空,直接在上面建树
每次删除操作,把要删除的点转到一棵子树上,直接删除
没几次默写 s p l a y splay splay,写挂了,调不出来
写代码时一定要认真,写错一个半天都调不出来!!!
变量一定要附初值!!!
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(x=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=2e6+4;
int ch[N][2],fa[N],siz[N],rt,a[N],cnt=0;
char c[N],s[N];
inline int pushup(int p){
siz[p]=siz[ch[p][1]]+siz[ch[p][0]]+1;
}
inline bool getson(int p){
return ch[fa[p]][1]==p;
}
inline void rotate(int p){
int f=fa[p],g=fa[f],r=getson(p);
if(f!=rt)ch[g][getson(f)]=p;fa[p]=g;//
ch[f][r]=ch[p][r^1];if(ch[f][r])fa[ch[f][r]]=f;
ch[p][r^1]=f;fa[f]=p;
pushup(f);pushup(p);
}
inline void splay(int x,int y){
for(;fa[x]!=y;rotate(x)){
if(fa[fa[x]]!=y)rotate(getson(x)==getson(fa[x])?fa[x]:x);
// printf("%d %d %d\n",x,fa[x],y);
}
if(!y)rt=x;
}
inline int find(int p,int pos){
if(siz[ch[p][0]]+1==pos)return p;
if(pos<=siz[ch[p][0]])return find(ch[p][0],pos);
return find(ch[p][1],pos-siz[ch[p][0]]-1);
}
inline void build(int l,int r,int f,int fn,char *s){
if(l>r)return;
int mid=(l+r)>>1,t;
++cnt;t=cnt;
if(l!=r){build(l,mid-1,t,0,s);build(mid+1,r,t,1,s);}
a[t]=s[mid];fa[t]=f;ch[f][fn]=t;pushup(t);
}
inline void print(int p){
if(ch[p][0])print(ch[p][0]);
putchar(a[p]);
if(ch[p][1])print(ch[p][1]);
}
int main(){
char chh[20];
int T,x,y,l,r,gb=0,len,n;
chh[0]=chh[1]=chh[2]=a[0]=' ';
build(1,2,0,0,chh);
rt=1;
T=read();
while(T--){
scanf("%s",chh);
if(chh[0]=='M')gb=read();
if(chh[0]=='I'){
len=read();
n+=len;
s[0]=' ';
for(int i=1;i<=len;i++){
s[i]=getchar();
if(s[i]=='\n'||s[i]=='\r')--i;
}
x=find(rt,gb+1);y=find(rt,gb+2);
splay(x,0);splay(y,x);
build(1,len,y,0,s);
}
if(chh[0]=='D'){
len=read();len=min(len,n-gb);n-=len;
x=find(rt,gb+1);y=find(rt,gb+len+2);
splay(x,0);splay(y,x);ch[y][0]=0;
}
if(chh[0]=='G'){
len=read();
len=min(len,n-gb);
x=find(rt,gb+1),y=find(rt,gb+len+2);
splay(x,0);splay(y,x);print(ch[y][0]);puts("");
}
if(chh[0]=='P')--gb;
if(chh[0]=='N')++gb;
}
return (0-0);
}
未调试出的代码
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(x=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=2e6+4;
char c[10];
string s;
int ch[N][2],siz[N],a[N],fa[N],cnt=0,rt=0;
inline int newnode(int x){
a[++cnt]=x;siz[cnt]=1;
return cnt;
}
inline void pushnow(int p){
siz[p]=siz[ch[p][1]]+siz[ch[p][0]]+1;
}
inline bool getson(int p){
return ch[fa[p]][1]==p;
}
inline void rotate(int p){
int f=fa[p],g=fa[f],r=getson(p);
if(f!=rt)ch[g][getson(f)]=p;fa[p]=g;//
ch[f][r]=ch[p][r^1];if(ch[f][r])fa[ch[f][r]]=f;
ch[p][r^1]=f;fa[f]=p;
pushnow(f);pushnow(p);
}
inline void splay(int x,int y){
for(;fa[x]!=y;rotate(x))
if(fa[fa[x]]!=y)rotate(getson(x)==getson(fa[x])?fa[x]:x);
if(!y)rt=x;
}
inline int find(int p,int pos){
printf("%d %d %d %d %d\n",p,siz[ch[p][0]],pos,ch[28][0],ch[33][0]);
cout<<(char)a[p]<<endl;
if(pos<=siz[ch[p][0]])return find(ch[p][0],pos);
if(pos==siz[ch[p][0]]+1)return p;
return find(ch[p][1],pos-siz[ch[p][0]]-1);
}
inline void delet(int pos){
pos=find(rt,pos);
splay(pos,0);
if(!ch[pos][0]){
rt=ch[pos][1];
fa[rt]=ch[pos][1]=0;
pushnow(rt);
return;
}
if(!ch[pos][1]){
rt=ch[pos][0];
fa[rt]=ch[pos][0]=0;
pushnow(rt);
return;
}
int x=find(rt,siz[ch[rt][0]]);
splay(x,rt);
ch[x][1]=ch[rt][1];if(ch[x][1])fa[ch[x][1]]=x;
ch[rt][1]=ch[rt][0]=fa[x]=0;rt=x;
pushnow(x);
}
inline void insert(int &p,int pos,int x){
if(!p)p=newnode(x);
else if(pos<=siz[ch[p][0]]){
insert(ch[p][0],pos,x);
fa[ch[p][0]]=p;//
}
else if(pos>siz[ch[p][0]]+1){
insert(ch[p][1],pos-siz[ch[p][0]]-1,x);//
fa[ch[p][1]]=p;//
}
else{
int r=p;
p=newnode(x);
fa[p]=fa[r];if(fa[p])ch[fa[p]][getson(r)]=p;
ch[p][1]=r;fa[r]=p;
ch[p][0]=ch[r][0];if(ch[p][0])fa[ch[p][0]]=p;ch[r][0]=0;
if(r==rt)rt=p;
pushnow(r);
}
pushnow(p);
}
int main(){
freopen("1.in","r",stdin);
// ios::sync_with_stdio(false);
// cin.tie(0);
int T=read(),x,gb=0,n=0;//哪个字符后
while(T--){
scanf("%s",c);
switch(c[0]){
case 'M':gb=read();break;
case 'I':{
x=read();
n+=x;
int len,all=0;
while(all<x){
getline(cin,s);
len=s.size();
for(int i=0;i<len;i++){
insert(rt,gb+1+all+i,s[i]);
splay(cnt,0);
}
all+=len;
}
break;
}
case 'D':{
x=read();
for(int i=1;i<=x;i++,n--){
if(gb==n)break;
delet(gb+1);
}
break;
}
case 'G':{
x=read();
for(int i=1;i<=x;i++){
cout<<i<<endl;
putchar((char)a[find(rt,gb+i)]);
}
putchar('\n');
break;
}
case 'P':if(gb)gb--;break;
case 'N':if(gb<n)gb++;break;
}
}
return (0-0);
}
洛谷P4567
支持操作
读入的时候直接 g e t c h a r getchar getchar即可
注: G E T GET GET操作如果得到的是’\n’,那么输出’\n’后无需再输出一个换行符
s p l a y splay splay
此题比上一道多了区间翻转,像文艺平衡书一样翻转即可
Y e a h ! Yeah! Yeah!
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(x=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=2e6+4;
int ch[N][2],fa[N],siz[N],rev[N],rt,a[N],cnt=0;
char c[N],s[N];
inline void pushdown(int p){
if(!rev[p])return;
swap(ch[p][0],ch[p][1]);
rev[ch[p][0]]^=1;rev[ch[p][1]]^=1;
rev[p]^=1;
}
inline void pushup(int p){
siz[p]=siz[ch[p][1]]+siz[ch[p][0]]+1;
}
inline bool getson(int p){
return ch[fa[p]][1]==p;
}
inline void rotate(int p){
int f=fa[p],g=fa[f],r=getson(p);
if(f!=rt)ch[g][getson(f)]=p;fa[p]=g;//
ch[f][r]=ch[p][r^1];if(ch[f][r])fa[ch[f][r]]=f;
ch[p][r^1]=f;fa[f]=p;
pushup(f);pushup(p);
}
inline void splay(int x,int y){
for(;fa[x]!=y;rotate(x))
if(fa[fa[x]]!=y)rotate(getson(x)==getson(fa[x])?fa[x]:x);
if(!y)rt=x;
}
inline int find(int p,int pos){
pushdown(p);
if(siz[ch[p][0]]+1==pos)return p;
if(pos<=siz[ch[p][0]])return find(ch[p][0],pos);
return find(ch[p][1],pos-siz[ch[p][0]]-1);
}
inline void build(int l,int r,int f,int fn,char *s){
if(l>r)return;
int mid=(l+r)>>1,t;
++cnt;t=cnt;
if(l!=r){build(l,mid-1,t,0,s);build(mid+1,r,t,1,s);}
a[t]=s[mid];fa[t]=f;ch[f][fn]=t;pushup(t);
}
int main(){
char chh[20];
int T,x,y,gb=0,len,n=0;
chh[0]=chh[1]=chh[2]=a[0]=' ';
build(1,2,0,0,chh);
rt=1;
T=read();
while(T--){
scanf("%s",chh);
if(chh[0]=='M')gb=read();
if(chh[0]=='I'){
len=read();
n+=len;
s[0]=' ';
for(int i=1;i<=len;i++)s[i]=getchar();
x=find(rt,gb+1);y=find(rt,gb+2);
splay(x,0);splay(y,x);
build(1,len,y,0,s);
}
if(chh[0]=='D'){
len=read();len=min(len,n-gb);n-=len;
x=find(rt,gb+1);y=find(rt,gb+len+2);
splay(x,0);splay(y,x);ch[y][0]=0;
}
if(chh[0]=='G'){
x=find(rt,gb+1),y=find(rt,gb+3);
splay(x,0);splay(y,x);putchar(a[ch[y][0]]);
if(a[ch[y][0]]!='\n'&&a[ch[y][0]]!='\r')puts("");
}
if(chh[0]=='P')--gb;
if(chh[0]=='N')++gb;
if(chh[0]=='R'){
len=read();len=min(len,n-gb);
x=find(rt,gb+1);y=find(rt,gb+len+2);
splay(x,0);splay(y,x);
rev[ch[y][0]]^=1;
}
}
return (0-0);
}
洛谷P1291
n n n个不同的数,每个数出现的概率相同,平均需要几次才能凑齐所有的数
用分数输出答案
数学期望
f [ k ] f[k] f[k]表示还剩 k k k个数没有的次数期望
f [ k ] = n − k n f [ k ] + k n f [ k − 1 ] + 1 f[k]=\frac{n-k}{n}f[k]+\frac{k}{n}f[k-1]+1 f[k]=nn−kf[k]+nkf[k−1]+1
f [ k ] = f [ k − 1 ] + n k f[k]=f[k-1]+\frac{n}{k} f[k]=f[k−1]+kn
期望入门题, t c l tcl tcl
l o n g l o n g longlong longlong用 l l d lld lld输出
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
#define int long long
inline int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
struct node{
int x,y;
inline void add(int e,int f){
x=x*f+y*e;y=y*f;
e=gcd(x,y);
x/=e;y/=e;
}
}ans;
int a,b,c,n;
inline int wei(int x){
int ret=0;
while(x){
x/=10;
ret++;
}
return ret;
}
signed main(){
n=read();
ans.x=0;ans.y=1;
for(int i=1;i<=n;i++)
ans.add(n,i);
a=ans.x/ans.y;
b=ans.x%ans.y;
c=ans.y;
if(!b){
printf("%lld",a);
return (0-0);
}
for(int i=1;i<=wei(a);i++)
printf(" ");
printf("%lld\n",b);
printf("%lld",a);
for(int i=1;i<=max(wei(b),wei(c));i++)
printf("-");
printf("\n");
for(int i=1;i<=wei(a);i++)
printf(" ");
printf("%lld",c);
return (0-0);
}
洛谷P1654
n n n个数的序列,每次有 p [ i ] p[i] p[i]的概率为1,否则为0,连续 x x x个1的贡献为 x x x3,求期望分数。
高次期望
先考虑一次的情况
a [ i ] = ( a [ i − 1 ] + 1 ) ∗ p [ i ] a[i]=(a[i-1]+1)*p[i] a[i]=(a[i−1]+1)∗p[i]
二次
b [ i ] = ( a [ i − 1 ] + 1 ) 2 ∗ p [ i ] b[i]=(a[i-1]+1)^2*p[i] b[i]=(a[i−1]+1)2∗p[i]
b [ i ] = ( b [ i − 1 ] + 2 ∗ a [ i − 1 ] + 1 ) ∗ p [ i ] b[i]=(b[i-1]+2*a[i-1]+1)*p[i] b[i]=(b[i−1]+2∗a[i−1]+1)∗p[i]
三次
f [ i ] = ( a [ i − 1 ] + 1 ) 3 ∗ p [ i ] f[i]=(a[i-1]+1)^3*p[i] f[i]=(a[i−1]+1)3∗p[i]
f [ i ] = ( f [ i − 1 ] + 3 ∗ b [ i − 1 ] + 3 ∗ a [ i − 1 ] + 1 ) ∗ p [ i ] f[i]=(f[i-1]+3*b[i-1]+3*a[i-1]+1)*p[i] f[i]=(f[i−1]+3∗b[i−1]+3∗a[i−1]+1)∗p[i]
但是并不能A,因为只考虑了当前点,并不是前i个点,所以
f [ i ] = ( f [ i − 1 ] + 3 ∗ b [ i − 1 ] + 3 ∗ a [ i − 1 ] + 1 ) ∗ p [ i ] + f [ i − 1 ] ∗ ( 1 − p [ i ] ) f[i]=(f[i-1]+3*b[i-1]+3*a[i-1]+1)*p[i]+f[i-1]*(1-p[i]) f[i]=(f[i−1]+3∗b[i−1]+3∗a[i−1]+1)∗p[i]+f[i−1]∗(1−p[i])
还要再看看……
为什么只有 f f f才考虑前 i i i和选到0的情况??
#include
using namespace std;
const int N=1e5+4;
int n;
double a[N],b[N],f[N],p;
//i位成功的一次期望 i位成功的二次期望 前i答案(三次期望)
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf",&p);
a[i]=(a[i-1]+1)*p;
b[i]=(b[i-1]+2*a[i-1]+1)*p;
f[i]=(f[i-1]+3*b[i-1]+3*a[i-1]+1)*p+f[i-1]*(1-p);
}
printf("%.1lf",f[n]);
return (0-0);
}
P4550
和百事世界杯之旅有点像,不过第 i i i次需要支付 i i i元钱,问花费的期望
高次期望
设需 x x x次
a n s = x 2 + x 2 ans=\frac{x^2+x}{2} ans=2x2+x
所以需求出一个一次和两次
一次同上
a [ i ] a[i] a[i]还要i种没得到
a [ i ] = a [ i − 1 ] + n i a[i]=a[i-1]+\frac{n}{i} a[i]=a[i−1]+in
二次
f [ i ] = n − i n ( f [ i ] + 2 ∗ a [ i ] + 1 ) + i n ( f [ i − 1 ] + 2 ∗ a [ i − 1 ] + 1 ) f[i]=\frac{n-i}{n}(f[i]+2*a[i]+1)+\frac{i}{n}(f[i-1]+2*a[i-1]+1) f[i]=nn−i(f[i]+2∗a[i]+1)+ni(f[i−1]+2∗a[i−1]+1)
f [ i ] = n − i i ( 2 ∗ a [ i ] + 1 ) + f [ i − 1 ] + 2 ∗ a [ i − 1 ] + 1 f[i]=\frac{n-i}{i}(2*a[i]+1)+f[i-1]+2*a[i-1]+1 f[i]=in−i(2∗a[i]+1)+f[i−1]+2∗a[i−1]+1
a n s = a [ n ] + f [ n ] 2 ans=\frac{a[n]+f[n]}{2} ans=2a[n]+f[n]
#include
using namespace std;
const int N=1e4+4;
double a[N],f[N];
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
a[i]=a[i-1]+n*1.0/i;
f[i]=(n-i)*1.0/i*(2*a[i]+1)+f[i-1]+2*a[i-1]+1;
}
printf("%.2lf",(a[n]+f[n])/2);
return (0-0);
}
洛谷P4716
求有向图的最小树形图
求最短弧集合E;(每条边找一条连向自己的最小边)
判断集合E中有没有有向环,如果有转步骤3,否则转4;
收缩点,把有向环收缩成一个点,并且对图重新构建,包括边权值的改变和点的处理,之后再转步骤1;
展开收缩点,求得最小树形图;
看看代码就懂了
还可以再看看
#include
using namespace std;
const int N=104,M=1e4+4,inf=0x3f3f3f3f;
struct edge{
int u,v,w;
}e[M];
int n,m,rt,ans=0,cnt,mn[N],from[N],vis[N],cn[N];
int main(){
scanf("%d%d%d",&n,&m,&rt);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
while(1){
memset(mn,0x3f,sizeof(mn));
for(int i=1,u,v,w;i<=m;i++){
u=e[i].u;v=e[i].v;w=e[i].w;
if(u!=v&&w<mn[v]){
mn[v]=w;from[v]=u;
}
}
for(int i=1;i<=n;i++)
if(i!=rt&&mn[i]==inf){
printf("-1");return (0-0);
}
cnt=0;
memset(vis,0,sizeof(vis));
memset(cn,0,sizeof(cn));
for(int i=1,v;i<=n;i++){
if(i==rt)continue;
ans+=mn[i];
v=i;
while(vis[v]!=i&&!cn[v]&&v!=rt){
vis[v]=i;
v=from[v];
}
if(!cn[v]&&v!=rt){
cn[v]=++cnt;
for(int j=from[v];j!=v;j=from[j])
cn[j]=cnt;
}
}
if(!cnt)break;
for(int i=1;i<=n;i++)
if(!cn[i])cn[i]=++cnt;
for(int i=1,u,v;i<=m;i++){
u=e[i].u;v=e[i].v;
e[i].u=cn[u];e[i].v=cn[v];
if(cn[u]!=cn[v])e[i].w-=mn[v];//代替之前的边
}
rt=cn[rt];
n=cnt;
}
printf("%d",ans);
return (0-0);
}
洛谷P4719
详见YY的PPT
线段树维护矩阵乘法
还要再学习!!!
引用记得加‘&’
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e5+4,inf=0x3f3f3f3f;
inline void MAX(int &x,int y){//!!!
x=(x>y)?x:y;
}
struct matrix{
int a[2][2];
inline matrix operator *(const matrix &x)const{
matrix ret;
for(int i=0;i^2;i++)//i<2
for(int j=0;j^2;j++){
ret.a[i][j]=-inf;
for(int k=0;k^2;k++)
MAX(ret.a[i][j],a[i][k]+x.a[k][j]);
}
return ret;
}
}t[N<<2],a[N];
struct edge{
int v,nxt;
}e[N<<1];
int first[N],cnt=0;
inline void add(int u,int v){
e[++cnt].v=v;e[cnt].nxt=first[u];first[u]=cnt;
}
int n,m,v[N];
int siz[N],fa[N],son[N],st[N],ed[N],top[N],idx[N],cn=0;
//ed[]每条重链的结束位置
#define lc (p<<1)
#define rc ((p<<1)|1)
inline void pushup(int p){
t[p]=t[lc]*t[rc];
}
inline void build(int p,int l,int r){
if(l==r){
t[p]=a[idx[l]];
return;
}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(p);
}
inline void modify(int p,int l,int r,int x){
if(l==r){
t[p]=a[idx[l]];
return;
}
int mid=l+r>>1;
if(x<=mid)modify(lc,l,mid,x);
else modify(rc,mid+1,r,x);
pushup(p);
}
inline matrix query(int p,int l,int r,int L,int R){
if(L<=l&&r<=R)return t[p];
int mid=l+r>>1;
if(L<=mid&&R>mid)return query(lc,l,mid,L,R)*query(rc,mid+1,r,L,R);
if(L<=mid)return query(lc,l,mid,L,R);
if(R>mid)return query(rc,mid+1,r,L,R);
}
inline void change(int p,int x){//??
a[p].a[1][0]+=x-v[p];//??
//gx0会随vi改变而改变
v[p]=x;
while(p){
matrix pre=query(1,1,n,st[top[p]],ed[top[p]]);
modify(1,1,n,st[p]);
matrix cur=query(1,1,n,st[top[p]],ed[top[p]]);
p=fa[top[p]];
matrix &xx=a[p];
xx.a[0][0]+=max(cur.a[0][0],cur.a[1][0])-max(pre.a[0][0],pre.a[1][0]);//??
xx.a[0][1]=xx.a[0][0];
xx.a[1][0]+=cur.a[0][0]-pre.a[0][0];
}
}
inline void dfs(int x){
siz[x]=1;
for(int i=first[x],v;i;i=e[i].nxt){
v=e[i].v;
if(v==fa[x])continue;
fa[v]=x;
dfs(v);
siz[x]+=siz[v];
if(siz[son[x]]<siz[v])son[x]=v;
}
}
inline pair<int,int> dfs(int x,int tp){//返回fx0,fx1
int gx0=0,gx1=0,fx0=0,fx1=0;
pair<int,int>p;
top[x]=tp;
st[x]=++cn;
idx[cn]=x;
fx1=gx1=v[x];
if(son[x]){
p=dfs(son[x],tp);
fx0+=max(p.first,p.second);
fx1+=p.first;
}
else ed[tp]=cn;
for(int i=first[x],v,y;i;i=e[i].nxt){
v=e[i].v;
if(v==fa[x]||v==son[x])continue;
p=dfs(v,v);
y=max(p.first,p.second);
gx0+=y;fx0+=y;
gx1+=p.first;fx1+=p.first;
}
a[x].a[0][0]=a[x].a[0][1]=gx0;
a[x].a[1][0]=gx1;a[x].a[1][1]=-inf;
// 矩阵情况
// | g_{i,0} g_{i,0} |
// R_i = | g_{i,1} -inf |
return make_pair(fx0,fx1);
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)v[i]=read();
for(int i=1,u,v;i<n;i++){
u=read();v=read();
add(u,v);add(v,u);
}
dfs(1);
dfs(1,1);
build(1,1,n);
for(int i=1,x,y;i<=m;i++){
x=read();y=read();
change(x,y);
matrix xx=query(1,1,n,st[1],ed[1]);
printf("%d\n",max(xx.a[0][0],xx.a[1][0]));
//根节点所在的重链底端的答案
}
return (0-0);
}
洛谷P4751
同动态DP,强制在线,卡树链剖分
全局平衡二叉树
重链建二叉树,轻边建虚边,只记父亲,不计儿子。
详见YY的PPT
!!! v o i d void void函数若写成 i n t int int会出现鬼畜错误, R E RE RE!!!!!!!!!
#include
using namespace std;
int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e6+4,inf=0x3f3f3f3f;
struct edge{
int v,nxt;
}e[N<<1];
int first[N],cnt=0;
void add(int u,int v){
e[++cnt].v=v;e[cnt].nxt=first[u];first[u]=cnt;
}
void MAX(int &x,int y){//!!!!!
x=(x>y?x:y);
}
struct matrix{
int a[2][2];
matrix(){
a[0][0]=a[1][0]=a[0][1]=a[1][1]=-inf;
}
int operator =(const int x){
return a[0][0]=a[1][1]=0;//
}
int* operator [](const int &x){
return a[x];
}
matrix operator *(const matrix &b)const{
matrix ret;
ret.a[0][0]=max(a[0][0]+b.a[0][0],a[0][1]+b.a[1][0]);
ret.a[0][1]=max(a[0][0]+b.a[0][1],a[0][1]+b.a[1][1]);
ret.a[1][0]=max(a[1][0]+b.a[0][0],a[1][1]+b.a[1][0]);
ret.a[1][1]=max(a[1][0]+b.a[0][1],a[1][1]+b.a[1][1]);//比循环快
return ret;//!!!
}
}w[N],mul[N];
int n,m,v[N],ans=0;
int siz[N],son[N];
void dfs(int x){
siz[x]=1;
for(int i=first[x],v;i;i=e[i].nxt){
v=e[i].v;
if(siz[v])continue;
dfs(v);
siz[x]+=siz[v];
if(siz[son[x]]<siz[v])son[x]=v;
}
}
int rt,vis[N],fa[N],s[N][2],sum[N],st[N];
void pushup(int p){
mul[p]=mul[s[p][0]]*w[p]*mul[s[p][1]];//
}
bool isson(int p){
return s[fa[p]][0]!=p&&s[fa[p]][1]!=p;
}
int build(int l,int r){
if(l>r)return 0;
int mid=lower_bound(sum+l,sum+r+1,(sum[r]-sum[l-1]-1)/2+1+sum[l-1])-sum;
int x=st[mid];
s[x][0]=build(l,mid-1);
s[x][1]=build(mid+1,r);
fa[s[x][0]]=fa[s[x][1]]=x;
pushup(x);
return x;
}
int tbuild(int x){
for(int i=x;i;i=son[i])
vis[i]=1;
for(int k=x,v,nwrt;k;k=son[k])
for(int i=first[k];i;i=e[i].nxt){
v=e[i].v;
if(vis[v])continue;
nwrt=tbuild(v);
fa[nwrt]=k;
w[k][0][0]+=max(mul[nwrt][0][0],mul[nwrt][1][0]);
w[k][0][1]=w[k][0][0];
w[k][1][0]+=mul[nwrt][0][0];
}
int len=0;
sum[0]=0;
for(int i=x;i;i=son[i]){
st[++len]=i;
sum[len]=sum[len-1]+siz[i]-siz[son[i]];//前缀和
}
return build(1,len);
}
void init(){
w[0]=mul[0]=0;
for(int i=1;i<=n;i++){
v[i]=w[i][1][0]=read();
w[i][0][0]=w[i][0][1]=0;
}
}
void modify(int p,int x){
w[p][1][0]+=x-v[p];
v[p]=x;
while(p){
int f=fa[p];
if(f&&isson(p)){//虚儿子
matrix pre=mul[p];
pushup(p);
matrix cur=mul[p];
w[f][0][0]+=max(cur[0][0],cur[1][0])-max(pre[0][0],pre[1][0]);
w[f][0][1]=w[f][0][0];
w[f][1][0]+=cur[0][0]-pre[0][0];
}
else pushup(p);
p=f;
}
}
int main(){
n=read();m=read();
init();
for(int i=1,u,v;i<n;i++){
u=read();v=read();
add(u,v);add(v,u);
}
dfs(1);
rt=tbuild(1);
for(int i=1,x,y;i<=m;i++){
x=read()^ans;
y=read();
modify(x,y);
printf("%d\n",ans=max(mul[rt][0][0],mul[rt][1][0]));
}
return (0-0);
}
P4173
AB两个字符串有些字符缺失,用*表示,可以是任何字符,问A在B中能匹配几次。
NTT
将通配字符设置为0;
g ( x ) = ∑ i = 1 m a [ x ] ∗ b [ x − i + 1 ] ∗ ( a [ x ] − b [ x − i + 1 ] ) 2 g(x)=\sum^{m}_{i=1}{a[x]*b[x-i+1]*(a[x]-b[x-i+1])^2} g(x)=i=1∑ma[x]∗b[x−i+1]∗(a[x]−b[x−i+1])2
g ( x ) = ∑ i = 1 m a [ x ] ∗ b [ x − i + 1 ] 3 − ∑ i = 1 m 2 ∗ a [ x ] 2 ∗ b [ x − i + 1 ] 2 + ∑ i = 1 m a [ x ] 3 ∗ b [ x − i + i ] g(x)=\sum^{m}_{i=1}a[x]*b[x-i+1]^3-\sum^{m}_{i=1}2*a[x]^2*b[x-i+1]^2+\sum^{m}_{i=1}a[x]^3*b[x-i+i] g(x)=i=1∑ma[x]∗b[x−i+1]3−i=1∑m2∗a[x]2∗b[x−i+1]2+i=1∑ma[x]3∗b[x−i+i]
将 x x x换成 m − x m-x m−x这样,加起来为定值方便卷积
g ( m + 1 ) = ∑ i = 1 m a [ m − x ] ∗ b [ x − i + 1 ] 3 − ∑ i = 1 m 2 ∗ a [ m − x ] 2 ∗ b [ x − i + 1 ] 2 + ∑ i = 1 m a [ m − x ] 3 ∗ b [ x − i + i ] g(m+1)=\sum^{m}_{i=1}a[m-x]*b[x-i+1]^3-\sum^{m}_{i=1}2*a[m-x]^2*b[x-i+1]^2+\sum^{m}_{i=1}a[m-x]^3*b[x-i+i] g(m+1)=i=1∑ma[m−x]∗b[x−i+1]3−i=1∑m2∗a[m−x]2∗b[x−i+1]2+i=1∑ma[m−x]3∗b[x−i+i]
分开把系数转点值,按式子算了之后再转系数
注意最后卷起来为两边下标相加, m − 1 m-1 m−1
将 x x x换成 m − x m-x m−x这样,加起来为定值方便卷积
注意最后卷起来为两边下标相加, m − 1 m-1 m−1
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
#define mod 998244353
#define ll long long
const int N=1e6+4;
inline int ksm(int x,int r){
int ret=1;
for(int i=0;(1<<i)<=r;i++){
if((1<<i)&r)ret=(ll)ret*x%mod;
x=(ll)x*x%mod;
}
return ret;
}
int rev[N<<1];
inline void NTT(int *a,int lim,int len,int fl){
for(int i=0;i<len;i++){
rev[i]=(rev[i>>1]>>1)|((i&1)<<lim-1);
if(i<rev[i])swap(a[i],a[rev[i]]);
}
for(int mid=1,tmp,x,u,v;mid<len;mid<<=1){
tmp=ksm(3,(mod-1)/(mid<<1));
if(fl==-1)tmp=ksm(tmp,mod-2);
for(int i=0;i<len;i+=(mid<<1)){
x=1;
for(int j=0;j<mid;j++,x=(ll)x*tmp%mod){
u=a[i+j];v=(ll)x*a[i+j+mid]%mod;
a[i+j]=(u+v)%mod;a[i+j+mid]=(u-v+mod)%mod;
}
}
}
}
int n,m,lim=0,len=1;
char aa[N],bb[N];
int a[N<<1],b[N<<1],A[N<<1],B[N<<1],C[N<<1],ans[N];
int main(){
m=read();n=read();
scanf("%s%s",aa,bb);
for(int i=0,j=m-1;i<m;i++,j--)
if(aa[j]!='*')a[i]=aa[j]-'a'+1;
for(int i=0;i<n;i++)
if(bb[i]!='*')b[i]=bb[i]-'a'+1;
while(len<m+n){
len<<=1;
lim++;
}
for(int i=0;i<len;i++){
A[i]=(ll)a[i]*a[i]*a[i]%mod;
B[i]=b[i];
}
NTT(A,lim,len,1);NTT(B,lim,len,1);
for(int i=0;i<len;i++)
C[i]=(ll)A[i]*B[i]%mod;
for(int i=0;i<len;i++){
A[i]=(ll)a[i]*a[i]%mod;
B[i]=(ll)b[i]*b[i]%mod;
}
NTT(A,lim,len,1);NTT(B,lim,len,1);
for(int i=0;i<len;i++)
C[i]=((ll)C[i]-(ll)2*A[i]*B[i]%mod+mod)%mod;
for(int i=0;i<len;i++){
A[i]=a[i];
B[i]=(ll)b[i]*b[i]*b[i]%mod;
}
NTT(A,lim,len,1);NTT(B,lim,len,1);
for(int i=0;i<len;i++)
C[i]=((ll)C[i]+(ll)A[i]*B[i]%mod)%mod;
NTT(C,lim,len,-1);
int tmp=ksm(len,mod-2);
for(int i=0;i+m-1<n;i++)
if(!(C[i+m-1]*tmp))ans[++ans[0]]=i+1;//
printf("%d\n",ans[0]);
for(int i=1;i<=ans[0];i++)
printf("%d ",ans[i]);
return (0-0);
}
洛谷P4180
求无向图的严格次小生成树
倍增
每次枚举加上一条边,删除环上最大边,由于严格次小,维护两个倍增数组,最大和次大,
复杂度 O ( n l o g m ) O(nlog_m) O(nlogm)
修改代码,一定要把所有相关的地方修改完!!!
#include
using namespace std;
#define int long long
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e5+4,M=3e5+4;
struct node{
int u,v,w,fl;
}a[M];
struct edge{
int v,w,nxt;
}e[N<<1];
int first[N],cnt=0;
inline void add(int u,int v,int w){
e[++cnt].v=v;e[cnt].w=w;
e[cnt].nxt=first[u];first[u]=cnt;
}
inline bool comp(const node &x,const node &y){
return x.w<y.w;
}
int n,m,fa[N][20],mx[N][20],fat[N],preans=0,ans=1e18,mx2[N][20];
//严格次小还要记次大值
inline int find(int x){
return x==fat[x]?x:fat[x]=find(fat[x]);
}
int dep[N];
inline void update(int &mx,int &mx2,int x,int y){
if(x>mx){mx2=mx;mx=x;}
else if(x>mx2&&mx!=x)mx2=x;
if(y>mx){mx2=mx;mx=y;}
else if(y>mx2&&mx!=y)mx2=y;
}
inline void predfs(int x){
for(int i=1;(1<<i)<=dep[x];i++){
fa[x][i]=fa[fa[x][i-1]][i-1];
update(mx[x][i],mx2[x][i],mx[x][i-1],mx2[x][i-1]);
update(mx[x][i],mx2[x][i],mx[fa[x][i-1]][i-1],mx2[fa[x][i-1]][i-1]);
}
for(int i=first[x],v;i;i=e[i].nxt){
v=e[i].v;
if(v==fa[x][0])continue;
fa[v][0]=x;
dep[v]=dep[x]+1;
mx[v][0]=e[i].w;
predfs(v);
}
}
inline int query(int x,int y,int d){
int ret=0,ret2=0,tmp;
if(dep[x]<dep[y])swap(x,y);
tmp=dep[x]-dep[y];
for(int i=0;(1<<i)<=tmp;i++)
if((1<<i)&tmp){
update(ret,ret2,mx[x][i],mx2[x][i]);
x=fa[x][i];
}
if(x==y)return ret==d?ret2:ret;//!!
for(int i=19;i>=0;i--)//
if(fa[x][i]!=fa[y][i]){
update(ret,ret2,mx[x][i],mx2[x][i]);
update(ret,ret2,mx[y][i],mx2[y][i]);
x=fa[x][i];y=fa[y][i];
}
update(ret,ret2,mx[x][0],mx2[x][0]);
update(ret,ret2,mx[y][0],mx2[y][0]);
return ret==d?ret2:ret;
}
signed main(){
n=read();m=read();
for(int i=1;i<=n;i++)fat[i]=i;
for(int i=1;i<=m;i++)
a[i]=(node){read(),read(),read(),0};
sort(a+1,a+m+1,comp);
for(int i=1,fu,fv;i<=m;i++){
fu=find(a[i].u);fv=find(a[i].v);
if(fu==fv)continue;
fat[fu]=fv;
a[i].fl=1;
preans+=a[i].w;
add(a[i].u,a[i].v,a[i].w);
add(a[i].v,a[i].u,a[i].w);
}
dep[1]=1;
predfs(1);
for(int i=1,t;i<=m;i++){
if(a[i].fl)continue;
t=preans+a[i].w-query(a[i].u,a[i].v,a[i].w);
if(t>preans&&t<ans)ans=t;
}
cout<<ans;
return (0-0);
}
洛谷3195
斜率优化
C k + + C_k++ Ck++
L + + L++ L++
费用为
( ∑ k = i j C k − L ) 2 (\sum^{j}_{k=i}{C_k}-L)^2 (k=i∑jCk−L)2
f [ i ] f[i] f[i]表示放前i的玩具需要的费用
f [ i ] = m i n ( f [ k ] + ( s [ i ] − s [ k − 1 ] − L ) 2 ) f[i]=min(f[k]+(s[i]-s[k-1]-L)^2) f[i]=min(f[k]+(s[i]−s[k−1]−L)2)
设 a [ i ] = s [ i ] − L ; b [ i ] = s [ i − 1 ] ; a[i]=s[i]-L;b[i]=s[i-1]; a[i]=s[i]−L;b[i]=s[i−1];
f [ i ] = m i n ( f [ k ] + a [ i ] 2 + b [ k ] 2 + 2 ∗ a [ i ] ∗ b [ k ] ) f[i]=min(f[k]+a[i]^2+b[k]^2+2*a[i]*b[k]) f[i]=min(f[k]+a[i]2+b[k]2+2∗a[i]∗b[k])
f [ k ] + b [ k ] 2 = 2 ∗ a [ i ] ∗ b [ k ] − a [ i ] 2 + f [ i ] f[k]+b[k]^2=2*a[i]*b[k]-a[i]^2+f[i] f[k]+b[k]2=2∗a[i]∗b[k]−a[i]2+f[i]
所以是一条斜率为 2 ∗ a [ i ] 2*a[i] 2∗a[i],截距为 a [ i ] 2 + f [ i ] a[i]^2+f[i] a[i]2+f[i]的直线
2 ∗ a [ i ] 2*a[i] 2∗a[i]单调递增,所以最优点组成的凸包斜率也因单调递增。
还不是很熟!!!!!!!!!!!
仔细思考
换元法降低式子复杂程度!!!
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
#define ll long long
const int N=5e4+4;
int n,L;
ll a[N],f[N];
inline ll s1(int x){
return a[x]+x;
}
inline ll s2(int x){
return s1(x)+L+1;
}
inline ll X(int x){
return s2(x);
}
inline ll Y(int x){
return f[x]+s2(x)*s2(x);
}
inline double check(int x,int y){
return ((double)Y(x)-Y(y))/(X(x)-X(y));
}
int head=1,tail=1,q[N];
int main(){
n=read();L=read();
for(int i=1;i<=n;i++)
a[i]=read()+a[i-1];
for(int i=1;i<=n;i++){
while(head<tail&&check(q[head],q[head+1])<2*s1(i))head++;
f[i]=f[q[head]]+(s1(i)-s2(q[head]))*(s1(i)-s2(q[head]));
while(head<tail&&check(i,q[tail-1])<check(q[tail-1],q[tail]))tail--;
q[++tail]=i;
}
cout<<f[n];
return (0-0);
}
求删去一条边后,无向图的最小生成树
先求出最小生成树
若删去不在树上的边就不管
考虑加上某一条边后,哪些边就可以删除了,一定是两个端点在树上路径上的边,于是用树链剖分维护路径最小值。
之前做起的题,现在都不会了~~~
#include
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=3e5+4;
struct edge{
int u,v,w,nxt,id;
}a[N],e[N<<1];
int first[N],cnt=0;
int n,m,q,fa[N],use[N],dy[N];
inline bool comp(const edge &x,const edge &y){
return x.w<y.w;
}
inline int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline int add(int u,int v,int w){
e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;
e[cnt].nxt=first[u];first[u]=cnt;
}
int siz[N],dep[N],son[N],pos[N],idx[N],top[N],pos_ed[N],tot=1;
inline void dfs1(int u){
siz[u]=1;
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa[u])continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
inline void dfs2(int u){
if(son[u]){
pos[son[u]]=++tot;
idx[pos[son[u]]]=son[u];
top[son[u]]=top[u];
dfs2(son[u]);
}
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa[u]||v==son[u])continue;
pos[v]=++tot;
idx[pos[v]]=v;
top[v]=v;
dfs2(v);
}
pos_ed[u]=tot;
}
#define ll long long
#define lc (p<<1)
#define rc (p<<1|1)
struct node{
int l,r,lazy,sum;
}t[(N<<2)];
inline void build(int p,int l,int r){
t[p].l=l;t[p].r=r;t[p].lazy=2e9;t[p].sum=2e9;
if(l==r)return;
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
}
inline void init(){
dfs1(1);
top[1]=idx[1]=1;
pos[1]=tot=1;
dfs2(1);
build(1,1,n);
}
inline void pushdown(int p){
if(t[p].lazy==2e9)return;
t[lc].sum=min(t[lc].sum,t[p].lazy);
t[lc].lazy=min(t[lc].lazy,t[p].lazy);
t[rc].sum=min(t[rc].sum,t[p].lazy);
t[rc].lazy=min(t[rc].lazy,t[p].lazy);
t[p].lazy=2e9;
}
inline void add1(int p,int l,int r,int v){
if(l<=t[p].l&&t[p].r<=r){
t[p].sum=min(t[p].sum,v);
t[p].lazy=min(t[p].lazy,v);
return;
}
pushdown(p);
int mid=t[p].l+t[p].r>>1;
if(l<=mid)add1(lc,l,r,v);
if(mid<r)add1(rc,l,r,v);
t[p].sum=min(t[lc].sum,t[rc].sum);
}
inline int query(int p,int l,int r){
if(l<=t[p].l&&t[p].r<=r)
return t[p].sum;
pushdown(p);
int mid=t[p].l+t[p].r>>1,ans=2e9;
if(l<=mid)ans=min(ans,query(lc,l,r));
if(mid<r)ans=min(ans,query(rc,l,r));
return ans;
}
inline void pathadd(int u,int v,int w){
if(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
pathadd(fa[top[u]],v,w);
add1(1,pos[top[u]],pos[u],w);
return;
}
if(dep[u]>dep[v])swap(u,v);
add1(1,pos[u]+1,pos[v],w);//
}
int main(){
int size = 8 << 20;
char *p = (char*)malloc(size) + size;
__asm__("movl %0, %%esp\n" :: "r"(p));
n=read();m=read();
for(int i=1;i<=m;i++){
a[i].u=read();a[i].v=read();a[i].w=read();a[i].id=i;
}
sort(a+1,a+m+1,comp);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++)dy[a[i].id]=i;
int ans=0,rr=1;
for(int i=1,u,v,fu,fv;i<=m;i++){
fu=find(a[i].u);fv=find(a[i].v);
if(fu!=fv){
add(a[i].u,a[i].v,a[i].w);add(a[i].v,a[i].u,a[i].w);
fa[fu]=fv;
rr++;
ans+=a[i].w;
use[i]=1;
}
}
memset(fa,0,sizeof(fa));
init();
for(int i=1;i<=m;i++){
if(use[i])continue;
pathadd(a[i].u,a[i].v,a[i].w);
}
q=read();
for(int i=1,x,u,v,r;i<=q;i++){
x=dy[read()];
if(rr<n){printf("Not connected\n");continue;}
if(!use[x]){printf("%d\n",ans);continue;}
u=a[x].u;v=a[x].v;
if(dep[u]<dep[v])swap(u,v);
r=query(1,pos[u],pos[u]);
if(r==2e9)printf("Not connected\n");
else printf("%d\n",ans-a[x].w+r);
}
return (0-0);
}