@01010101
2018-11-05T13:37:26.000000Z
字数 5043
阅读 1104
noip
DAY1T1玩具谜题
按题意模拟即可。
DAY1T2天天爱跑步
开始少考虑了一种情况。
确实是需要树上差分的。
少的情况:
s和t都在以fa[lca]为根的子树中。但此时s和t不能对fa[lca]产生贡献。
这就是树上差分和树上直接用桶维护的区别。
桶的要求是子树中的每个值都能对答案产生贡献。
树上差分:只对u到v的路径上的点有贡献。(对lca以上的点没有贡献)。
#include <iostream>#include <cstdio>#include <cstring>#include <vector>using namespace std;int read(){char ch;int op=1;while((ch=getchar())<'0'||ch>'9') if(ch=='-') op=-1;int ret=ch-'0';while((ch=getchar())>='0'&&ch<='9') ret=ret*10+ch-'0';return ret*op;}void write(int x){if(x<0) putchar('-'),x=-x;if(x>=10) write(x/10);putchar('0'+x%10);}const int N=300000+10;const int D=25;int n,m,kk;int s[N],t[N],w[N],vis[N],val[N],dep[N],head[N],A[N<<1],B[N<<1],f[N][D+2];struct edge{int v,nxt;}e[N<<1];void adde(int u,int v){e[kk].v=v;e[kk].nxt=head[u];head[u]=kk++;}vector <int> v[N];vector <int> vec[N];vector <int> vst[N];void dfs(int u,int fa){dep[u]=dep[fa]+1;f[u][0]=fa;for(int i=1;i<=D;++i)f[u][i]=f[f[u][i-1]][i-1];for(int i=head[u];i!=-1;i=e[i].nxt)if(e[i].v!=fa)dfs(e[i].v,u);}int lca(int u,int v){if(dep[u]<dep[v]) swap(u,v);for(int i=D;i>=0;--i)if(dep[f[u][i]]>=dep[v])u=f[u][i];if(u==v) return u;for(int i=D;i>=0;--i)if(f[u][i]!=f[v][i]){u=f[u][i];v=f[v][i];}return f[u][0];}void dfs1(int u,int fa){int tmpa=A[dep[u]+w[u]];int tmpb=B[w[u]-dep[u]+n];for(int i=head[u];i!=-1;i=e[i].nxt){int v=e[i].v;if(v!=fa){dfs1(v,u);}}if(vis[u]) A[dep[u]]+=vis[u];int sz=v[u].size();for(int i=0;i<sz;++i){B[v[u][i]+n]++;}val[u]+=A[dep[u]+w[u]]-tmpa;val[u]+=B[w[u]-dep[u]+n]-tmpb;sz=vec[u].size();for(int i=0;i<sz;++i){B[vec[u][i]+n]--;}sz=vst[u].size();for(int i=0;i<sz;++i){A[vst[u][i]]--;}}int main(){// freopen("test.in","r",stdin);// freopen("test.out","w",stdout);int a,b,l;memset(head,-1,sizeof(head));n=read();m=read();for(int i=1;i<n;++i){a=read();b=read();adde(a,b);adde(b,a);}for(int i=1;i<=n;++i){w[i]=read();}dfs(1,0);for(int i=1;i<=m;++i){s[i]=read();t[i]=read();l=lca(s[i],t[i]);if(l!=s[i]&&l!=t[i]){vis[s[i]]++;vst[l].push_back(dep[s[i]]);v[t[i]].push_back(dep[s[i]]-2*dep[l]);vec[l].push_back(dep[s[i]]-2*dep[l]);if(dep[l]+w[l]==dep[s[i]]) val[l]--;}else {if(l==s[i]&&l!=t[i]){v[t[i]].push_back(-dep[s[i]]);vec[l].push_back(-dep[s[i]]);}else if(l==t[i]&&l!=s[i]){vis[s[i]]++;vst[l].push_back(dep[s[i]]);}else{if(w[s[i]]==0) val[s[i]]++;}}}dfs1(1,0);for(int i=1;i<=n;++i){write(val[i]);putchar(' ');}return 0;}
DAY1T3换教室
相对简单的概率dp,一定要把所有情况列举出来
dp[i][j][1/0] 表示到第i节课,换了j节课,1表示当前申请了换课,0表示当前没申请换课
1.当前的课不换的情况:(1)上一节课也没换;(2)上一节课换了----成功or不成功;
2.当前的课换的情况:
(1)当前课成功换了:a.上一节课换了----上一节课成功or不成功b.上一节课没换;
(2)当前的课换了失败:a.上一节课换了----上一节课成功or不成功b.上一节课没换;
DAY2T1组合数问题
法一:先把K分解质因数,然后二维递推每个组合数中含这些因子的情况。(先处理每个数,在处理组合数),最后O(1)查询。(主要是观察到K最大为21,质因数就2个)
法二:预处理杨辉三角(模k),然后处理出二维前缀和,最后O(1)查询。
DAY2T2蚯蚓
关键是要发现强制增长的性质。一段蚯蚓在切断后之前的增长就没有了,然后就开始想取维护一个标记,表示在什么时候开始增长。可是这样就不能保证用优先队列找出的最大值准确。(好像也可以,在重定义小于符号的时候用(当前时刻-开始累计的时刻)*系数+开始长度)。所以就让每个蚯蚓强制从时刻1开始增长,所以最开始的长度可能是负数。
最开始想用线段树求第K大。但是高达1e8就没有办法了,而且如果强制增长会出现负数。也没有办法离散化。
开始没注意数据范围就用优先队列了,TLE了3个点。
看了题解发现就是一个小性质。维护3个队列。第一个是原队列,第二个是切后长蚯蚓队列,第三个是切后短蚯蚓队列。这三个队列分别满足单调性。
queue <int> q[3];int main(){// freopen("a.txt","r",stdin);n=read();m=read();qq=read();u=read();v=read();t=read();p=(double)u/v;for(int i=1;i<=n;++i) a[i]=read();sort(a+1,a+n+1);for(int i=1;i<=n;++i) q[0].push(a[n-i+1]);while(m--){A=-INF;B=-INF;C=-INF;if(!q[0].empty())A=q[0].front();if(!q[1].empty())B=q[1].front();if(!q[2].empty())C=q[2].front();if(A>=B&&A>=C){ps=A;q[0].pop();}else if(B>=A&&B>=C){ps=B;q[1].pop();}else {ps=C;q[2].pop();}ps+=delta;if(++cnt==t){cnt=0;write(ps);putchar(' ');}nw1=ps*p,nw2=ps-nw1;delta+=qq;nw1-=delta;nw2-=delta;if(nw1>=nw2){q[1].push(nw1);q[2].push(nw2);}else{q[1].push(nw2);q[2].push(nw1);}}putchar('\n');cnt=0;while(!q[0].empty()||!q[1].empty()||!q[2].empty()){A=-INF;B=-INF;C=-INF;if(!q[0].empty())A=q[0].front();if(!q[1].empty())B=q[1].front();if(!q[2].empty())C=q[2].front();if(A>=B&&A>=C){ps=A;q[0].pop();}else if(B>=A&&B>=C){ps=B;q[1].pop();}else {ps=C;q[2].pop();}if(++cnt==t){ps+=delta;cnt=0;write(ps);putchar(' ');}}return 0;}
DAY2T3愤怒的小鸟
状压。没有想象中的难。
关键在于要发现三点可以确定一条抛物线。一点是起点,所以我们定义一条抛物线就是cover[i][j]就是经过i点和j点的那条抛物线经过的点的集合(状压)。
int main(){T=read();while(T--){n=read();m=read();t=(1<<n)-1;for(int i=1;i<=n;++i)scanf("%lf%lf",&a[i].x,&a[i].y);memset(cover,0,sizeof(cover));for(int i=1;i<=n;++i){cover[i][i]=(1<<(i-1));double xi=a[i].x,yi=a[i].y;for(register int j=1;j<=n;++j){if(fabs(a[i].x-a[j].x)<eps) continue;double xj=a[j].x,yj=a[j].y;double B=(yj*xi*xi-yi*xj*xj)/(xi*xi*xj-xi*xj*xj);double A=(yi-xi*B)/(xi*xi);if(A>-eps) continue;for(register int k=1;k<=n;++k)if(fabs(a[k].y-A*a[k].x*a[k].x-B*a[k].x)<eps)cover[i][j]|=(1<<(k-1));}}memset(dp,INF,sizeof(dp));dp[0]=0;for(register int i=1;i<=n;++i)for(register int j=0;j<=t;++j)if(dp[j]<INF)for(register int k=1;k<=n;++k)dp[(j|cover[i][k])]=min(dp[(j|cover[i][k])],dp[j]+1);printf("%d\n",dp[t]);}return 0;}
由此,noip2016所有题就写完了。
模拟
树上差分
概率dp
数学
数据结构(队列)+思维
状压dp