NOIP2016提高組換教室
洛谷P1850
題意
兩個序列,,你需依次走過這個點,如果申請,則有i 的機會將i 換成i,但你只能申請次,求走過這個點的路徑總和的期望最小值。
方法
期望
表示走過前個點,當前點是否申請的期望
??
如果寫成
會精度丟失,WA3個點
心得
終於會期望了,不過對於精度丟失很懵逼
數組一定要清零,以免用到一些不存在的狀態!!!
代碼
#include<bits/stdc++.h>
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);
}
文藝平衡樹(splay)
洛谷P3391
題意
區間翻轉,輸出最終區間
方法
下標建樹,對於翻轉的區間,通過形成一棵子樹,打翻轉標記,時交換左右兒子,只有在時才?
代碼
#include<bits/stdc++.h>
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;
}
NOI2003文本編輯器
洛谷P4008
題意
支持操作
方法
每次插入把根節點的右兒子的左兒子弄空,直接在上面建樹
每次刪除操作,把要刪除的點轉到一棵子樹上,直接刪除
心得
沒幾次默寫,寫掛了,調不出來
寫代碼時一定要認真,寫錯一個半天都調不出來!!!
變量一定要附初值!!!
代碼
#include<bits/stdc++.h>
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<bits/stdc++.h>
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);
}
[AHOI2006]文本編輯器
洛谷P4567
題意
支持操作
讀入的時候直接即可
注:操作如果得到的是’\n’,那麼輸出’\n’後無需再輸出一個換行符
方法
此題比上一道多了區間翻轉,像文藝平衡書一樣翻轉即可
心得
代碼
#include<bits/stdc++.h>
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);
}
[SHOI2002]百事世界盃之旅
洛谷P1291
題意
個不同的數,每個數出現的概率相同,平均需要幾次才能湊齊所有的數
用分數輸出答案
方法
數學期望
表示還剩個數沒有的次數期望
心得
期望入門題,
用輸出
代碼
#include<bits/stdc++.h>
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);
}
OSU!
洛谷P1654
題意
個數的序列,每次有的概率爲1,否則爲0,連續個1的貢獻爲3,求期望分數。
方法
高次期望
先考慮一次的情況
二次
三次
但是並不能A,因爲只考慮了當前點,並不是前i個點,所以
心得
還要再看看……
??
爲什麼只有才考慮前和選到0的情況??
代碼
#include<bits/stdc++.h>
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種沒得到
二次
代碼
#include<bits/stdc++.h>
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<bits/stdc++.h>
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);
}
動態DP
洛谷P4719
題意
方法
詳見YY的PPT
線段樹維護矩陣乘法
心得
還要再學習!!!
引用記得加‘&’
代碼
#include<bits/stdc++.h>
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);
}
動態DP(加強版)
洛谷P4751
題意
同動態DP,強制在線,卡樹鏈剖分
方法
全局平衡二叉樹
重鏈建二叉樹,輕邊建虛邊,只記父親,不計兒子。
詳見YY的PPT
心得
!!!函數若寫成會出現鬼畜錯誤,!!!!!!!!!
代碼
#include<bits/stdc++.h>
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;
將換成這樣,加起來爲定值方便卷積
分開把係數轉點值,按式子算了之後再轉系數
注意最後捲起來爲兩邊下標相加,
心得
將換成這樣,加起來爲定值方便卷積
注意最後捲起來爲兩邊下標相加,
代碼
#include<bits/stdc++.h>
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);
}
嚴格次小生成樹[BJWC2010]
洛谷P4180
題意
求無向圖的嚴格次小生成樹
方法
倍增
每次枚舉加上一條邊,刪除環上最大邊,由於嚴格次小,維護兩個倍增數組,最大和次大,
複雜度
心得
修改代碼,一定要把所有相關的地方修改完!!!
代碼
#include<bits/stdc++.h>
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);
}
[HNOI2008]玩具裝箱TOY
洛谷3195
題意
方法
斜率優化
費用爲
表示放前i的玩具需要的費用
設
所以是一條斜率爲,截距爲的直線
單調遞增,所以最優點組成的凸包斜率也因單調遞增。
心得
還不是很熟!!!!!!!!!!!
仔細思考
換元法降低式子複雜程度!!!
代碼
#include<bits/stdc++.h>
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<bits/stdc++.h>
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);
}