学大伟业 2017 国庆 Day1
期望得分:100+100+20=220
实际得分:100+100+20=220
(好久没有期望==实际了 ,~\(≧▽≦)/~)
对于 a。。。。。。。。a
如果 第1个a 后面出现的第1个b~z 是右端点,且在第2个a之前,那么有贡献
如果 第2个a 前面出现的第1个b~z 是左端点,且在第1个a之后,那么有贡献
最后的贡献/2
#include<cstdio> #include<cstring> #define N 100001 using namespace std; char s[N]; int LAST[26],last[N],pre[N][26],suf[N][26]; bool w[N],c[26]; int main() { freopen("cross.in","r",stdin); freopen("cross.out","w",stdout); scanf("%s",s+1); int len=strlen(s+1),ans=0,ch; for(int i=1;i<=len;i++) for(int j=0;j<26;j++) if(s[i]-'a'==j) pre[i][j]=i; else pre[i][j]=pre[i-1][j]; for(int i=0;i<26;i++) suf[len][i]=len+1; suf[len][s[len]-'a']=len; for(int i=len-1;i;i--) for(int j=0;j<26;j++) if(s[i]-'a'==j) suf[i][j]=i; else suf[i][j]=suf[i+1][j]; for(int i=1;i<=len;i++) { ch=s[i]-'a'; c[ch]^=1; w[i]=!c[ch]; if(c[ch]) LAST[ch]=i; else last[i]=LAST[ch]; } for(int i=1;i<=len;i++) if(w[i]) { for(int j=0;j<26;j++) if(j!=s[i]-'a') { if(suf[last[i]][j]<i && w[suf[last[i]][j]]) ans++; if(pre[i][j]>last[i] && !w[pre[i][j]]) ans++; } } printf("%d",ans>>1); }
dis[i][j] 表示 到第i个点,用了j次传送的最快时间
堆优化的dijkstra
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 501 #define M 2001 int n,m,g,k; int front[N],to[M<<1],nxt[M<<1],val[M<<1],tot; bool fly[M<<1]; int DIS[N][2001]; struct node { int tim,dis,num; bool operator < (node p) const { return dis>p.dis; } }cur,nt; priority_queue<node>q; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v,int w,bool fl) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w; fly[tot]=fl; } void init() { read(n); read(m); read(g); read(k); int u,v,w; k=min(g,k); while(m--) { read(u); read(v); read(w); add(u,v,w,0); } while(g--) { read(u); read(v); read(w); add(u,v,w,1); } } void dijkstra() { memset(DIS,63,sizeof(DIS)); cur.dis=0; cur.num=1; cur.tim=0; DIS[1][0]=0; q.push(cur); while(!q.empty()) { cur=q.top(); q.pop(); if(cur.num==n) { printf("%d",cur.dis); return; } if(DIS[cur.num][cur.tim]!=cur.dis) continue; for(int i=front[cur.num];i;i=nxt[i]) { if(DIS[to[i]][cur.tim+fly[i]]<cur.dis+val[i]) continue; if(cur.tim+fly[i]>k) continue; DIS[to[i]][cur.tim+fly[i]]=cur.dis+val[i]; nt.dis=cur.dis+val[i]; nt.tim=cur.tim+fly[i]; nt.num=to[i]; q.push(nt); } } printf("-1"); } int main() { freopen("move.in","r",stdin); freopen("move.out","w",stdout); init(); dijkstra(); return 0; }
相当于把树分成许多块,每一个块的大小>=k,求分块方案数
树上背包
dp[i][j] 以i为根子树内,块的大小为j的方案数
g[j] 当前大小为j的块的方案数
cnt[i] 以i为根节点的块,大小>=k的方案数
假设当前正在合并u的子节点 v
v所在块 如果本身就>=k,那么v可以不并入u,g[j]=cnt[v]*dp[u][j]
枚举已经与u合并的块的大小j
枚举v所在块的大小h
g[j+h]+=dp[x][j]*dp[v][h]
合并u和v,把g赋给dp
最后处理完u的时候更新cnt
注意师最后合并,这样可以使时间复杂度降到 n^2
相当于每对点只在LCA处有贡献
#include<cstdio> #include<iostream> using namespace std; #define N 5001 #define mod 786433 int front[N],to[N<<1],nxt[N<<1],tot; int siz[N],dp[N][N],g[N],cnt[N]; int k; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; } void init() { int n; read(n); read(k); int u,v; for(int i=1;i<n;i++) { read(u); read(v); add(u,v); } } void dfs(int x,int y) { siz[x]=1; dp[x][1]=1; for(int i=front[x];i;i=nxt[i]) if(to[i]!=y) { dfs(to[i],x); for(int j=1;j<=siz[x]+siz[to[i]];j++) g[j]=0; for(int j=1;j<=siz[x];j++) g[j]=1ll*cnt[to[i]]*dp[x][j]%mod; for(int j=1;j<=siz[x];j++) for(int h=1;h<=siz[to[i]];h++) g[j+h]=(g[j+h]+1ll*dp[x][j]*dp[to[i]][h]%mod)%mod; for(int j=1;j<=siz[x]+siz[to[i]];j++) dp[x][j]=g[j]; siz[x]+=siz[to[i]]; } for(int i=k;i<=siz[x];i++) cnt[x]+=dp[x][i],cnt[x]%=mod; } int main() { freopen("cut.in","r",stdin); freopen("cut.out","w",stdout); init(); dfs(1,0); int ans=0; for(int i=k;i<=siz[1];i++) ans+=dp[1][i],ans%=mod; printf("%d",ans); }
2^n 20分暴力
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 5001 int n,k; int front[N],to[N<<1],nxt[N<<1],from[N<<1],tot; int ans,cnt; bool use[N]; int siz[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; } void init() { read(n); read(k); int u,v; for(int i=1;i<n;i++) { read(u); read(v); add(u,v); } } void dfs2(int x,int y) { cnt++; for(int i=front[x];i;i=nxt[i]) if(to[i]!=y && use[i]) dfs2(to[i],x); } void judge() { for(int i=1;i<=n;i++) { cnt=0; dfs2(i,0); if(cnt<k) return; } ans++; } void dfs(int x) { if(x==(n-1)*2+1) { judge(); return; } dfs(x+2); use[x]=use[x+1]=true; dfs(x+2); use[x]=use[x+1]=false; } int main() { freopen("cut.in","r",stdin); freopen("cut.out","w",stdout); init(); dfs(1); printf("%d",ans); }