noip模拟33[进阶啦啦啦]
noip模拟33 solutions
不知道该咋说,这场考试其实是我这三四场以来最最最最最顺心的一场了
为啥呢?因为我这回思考有很多结果,得到了脑袋的回复
就是你想了半个小时就有了一点点头绪,那感觉就是"妙哉"
但是分数却不如人意,只有100pts,挂掉了55pts
按照现在的状态,下次肯定能A题
T1 Hunter
这个题还是一眼就有45pts,轻轻的状压一下,再加上记忆化搜索
半个小时45pts到手。
45pts·状压#include<bits/stdc++.h> using namespace std; #define re register int #define ll long long const int N=1e5+5; const ll mod=998244353; int n; ll w ,dp[1<<20]; ll ksm(ll x,ll y){ ll ret=1; while(y){ if(y&1)ret=ret*x%mod; x=x*x%mod; y>>=1; } return ret; } ll dfs(int x,int s){ if(x==n+1)return 1; if(dp[s])return dp[s]; ll tmp=0; for(re i=1;i<=n;i++){ if((s>>i-1)&1)continue; tmp=(tmp+w[i])%mod; } ll bas=ksm(tmp,mod-2); for(re i=1;i<=n;i++){ if((s>>i-1)&1)continue; if(i==1)dp[s]=(dp[s]+w[i]*bas%mod*x%mod)%mod; else dp[s]=(dp[s]+w[i]*bas%mod*dfs(x+1,s|(1<<i-1)%mod))%mod; } return dp[s]; } signed main(){ scanf("%d",&n); for(re i=1;i<=n;i++) scanf("%lld",&w[i]); printf("%lld",dfs(1,0)); }
但是接下来的质的飞跃就比较难受,但是看完题解之后整个人都傻掉了
所以说,对于期望这个东西咋转移都没事
毕竟这个期望是具有线性性的,怎么加都可以,然后这个题就直接做出来了
我们知道第一个猎人死在第几次,那么就是在他前面死的人的个数+1
下面就是求期望有多少人死在他前面,
如果当前这个人还没有死,那么这个人死在1号猎人之前的概率就是$\frac{w_1+w_i}$
因为每死一个就会造成1的贡献,所以期望就是概率
不需要考虑别人的死法,因为这个i包含了所有的其他的猎人
这样考虑的原因还有一个,就是死的概率和谁开枪没有关系,只和当前谁剩下有关
AC_code#include<bits/stdc++.h> using namespace std; #define re register int #define ll long long const int N=1e5+5; const ll mod=998244353; int n; ll w ,dp[1<<20]; ll ksm(ll x,ll y){ ll ret=1; while(y){ if(y&1)ret=ret*x%mod; x=x*x%mod; y>>=1; } return ret; } ll ans; signed main(){ scanf("%d",&n); for(re i=1;i<=n;i++) scanf("%lld",&w[i]); for(re i=2;i<=n;i++){ ans=(ans+w[i]*ksm(w[i]+w[1],mod-2)%mod)%mod; } printf("%lld",ans+1); }
这个题其实非常的水,只要充分理解期望就好了。。
T2 Defence
我这个题考场上一眼切了,直接线段树合并+维护最长区间
这个题之前做过好多次了
这次就维护区间内最长的0就好了。。。。不难吧
注意维护的时候,最后的答案是max(区间内最长的,左右最长的之和)这个可以看代码实现
因为初始全部是0,所以这里的pushup有一些玄学,
如果看不懂可以去网上求救一下其他人的维护1的长度的做法
AC_code#include<bits/stdc++.h> using namespace std; #define re register int #define ll long long const int N=1e5+5; int n,m,q; int to ,nxt ,head ,rp; void add_edg(int x,int y){ to[++rp]=y; nxt[rp]=head[x]; head[x]=rp; } struct XDS{ int mmx[N*80],rmx[N*80],lmx[N*80]; int ls[N*80],rs[N*80]; int seg; void pushup(int x,int l,int r){ if(!ls[x]&&!rs[x])return ; int mid=l+r>>1; if(ls[x]&&rs[x]){ mmx[x]=max(lmx[rs[x]]+rmx[ls[x]],max(mmx[rs[x]],mmx[ls[x]])); lmx[x]=lmx[ls[x]]; if(lmx[ls[x]]==mid-l+1)lmx[x]=lmx[ls[x]]+lmx[rs[x]]; rmx[x]=rmx[rs[x]]; if(rmx[rs[x]]==r-mid)rmx[x]=rmx[rs[x]]+rmx[ls[x]]; } if(ls[x]&&!rs[x]){ mmx[x]=mmx[ls[x]]; lmx[x]=lmx[ls[x]]; if(lmx[ls[x]]==mid-l+1)lmx[x]=r-l+1; rmx[x]=rmx[ls[x]]+r-mid; } if(!ls[x]&&rs[x]){ mmx[x]=mmx[rs[x]]; lmx[x]=lmx[rs[x]]+mid-l+1; rmx[x]=rmx[rs[x]]; if(rmx[rs[x]]==r-mid)rmx[x]=r-l+1; } return ; } void ins(int &x,int l,int r,int pos){ if(!x)x=++seg; if(l==r)return ; int mid=l+r>>1; if(pos<=mid)ins(ls[x],l,mid,pos); else ins(rs[x],mid+1,r,pos); pushup(x,l,r); return ; } int merge(int x,int y,int l,int r){ if(!x||!y)return x+y; if(l==r)return x; int mid=l+r>>1; ls[x]=merge(ls[x],ls[y],l,mid); rs[x]=merge(rs[x],rs[y],mid+1,r); pushup(x,l,r); return x; } }xds; int rt ,ans ; void dfs(int x){ for(re i=head[x];i;i=nxt[i]){ int y=to[i];dfs(y); rt[x]=xds.merge(rt[x],rt[y],1,m); } if(!rt[x])ans[x]=-1; else ans[x]=max(xds.mmx[rt[x]],xds.lmx[rt[x]]+xds.rmx[rt[x]]); } signed main(){ scanf("%d%d%d",&n,&m,&q); for(re i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add_edg(x,y); } for(re i=1;i<=q;i++){ int x,y; scanf("%d%d",&x,&y); xds.ins(rt[x],1,m,y); } dfs(1); for(re i=1;i<=n;i++){ printf("%d\n",ans[i]); } }
所以说为什么我只有45pts嘞???
因为我没有判断-1,但是其实挺冤的。
考场上我明明自己造了一组数据有-1的情况,当时我的$code$输出的是0
然后我暴怒
这输出0怎么行呢,让他变成m
一顿乱搞,把所有的-1全判成了m,考后直接把m改成-1,AC\;AC\;AC\;AC
T3 Connect
最近总是在考试的时候遇到一些状压神题,昨天是二维,今天是带其他变量
真难!!!
理解了就非常的简单
我们要将所有的点都加入到当前的状态内,所以我们的dp第一维一定是点集
既然是dp,那么我们就可以直接枚举所有状态,而且这个题复杂度极其的小
设dp[i][j]表示当前点集为i,1-n的这个链的结尾是j,
当然你可能会认为,有可能j他不在这个链上啊啊,
大哥,这都是dp了,不在链上他能转移过去,枚举就完事了,而且你当时也不知道谁在谁不在
我们有两种情况一种是在当前点直接并入其他点集,但是这个点集中的点只可以跟当前j连边
为啥不可以跟前边连啊啊啊?因为前面的在前面已经计算过了,所以这里面有好多无用状态
但是他方便了你的转移
另外一种就之在j上再接一个点k,那么加入这个点后的点集的端点就是k啦,
为啥不能是j,因为你前面还会计算k在前面,j接在k后面的情况
dp就是dp,不需要考虑那么多好吧。。。。
AC_code#include<bits/stdc++.h> using namespace std; #define re register int const int N=20; int n,m; int dis ; int sum[1<<15]; int dp[1<<15][16],val[1<<15][16]; signed main(){ scanf("%d%d",&n,&m); for(re i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); dis[x][y]=dis[y][x]=z; } for(re i=1;i<(1<<n);i++) for(re j=1;j<=n;j++) for(re k=j+1;k<=n;k++) if(((i>>j-1)&1)&&((i>>k-1)&1))sum[i]+=dis[j][k]; for(re i=1;i<(1<<n);i++) for(re j=1;j<=n;j++){ if((i>>j-1)&1)continue; for(re k=1;k<=n;k++) if(((i>>k-1)&1)&&dis[j][k])val[i][j]+=dis[j][k]; } memset(dp,-1,sizeof(dp)); dp[1][1]=0; for(re i=1;i<(1<<n);i++){ for(re j=1;j<=n;j++){ if(dp[i][j]==-1)continue; for(re k=1;k<=n;k++){ if(((i>>k-1)&1)||!dis[j][k])continue; dp[i|(1<<k-1)][k]=max(dp[i|(1<<k-1)][k],dp[i][j]+dis[j][k]); } int tmp=(i^((1<<n)-1)); for(re k=tmp;k;k=(k-1)&tmp){ dp[i|k][j]=max(dp[i|k][j],dp[i][j]+val[k][j]+sum[k]); } } } cout<<sum[(1<<n)-1]<<" "<<dp[(1<<n)-1] <<endl; printf("%d",sum[(1<<n)-1]-dp[(1<<n)-1] ); }
- NOIP模拟测试33
- 洛谷 3938 [NOIP模拟] 斐波那契 二分+找规律
- 2548. 【NOIP2011模拟9.4】最大正方形 (Standard IO)
- 【NOIP2012模拟11.5】小A 的作业
- 2062. 【2016.10.4NOIP普及模拟】Bill
- 【NOIP2016提高A组模拟8.14】传送带
- 【NOIP2012模拟10.6】购买
- 洛谷 2827 [NOIP2016] 蚯蚓 队列模拟
- 【2016.10.5NOIP普及模拟】wd的假日
- 2069. 【2016.10.5NOIP普及模拟】wd的假日
- 2554. 【NOIP2011模拟9.7】帕秋莉·诺蕾姬 (Standard IO)
- 高中OJ3046. 【NOIP2012模拟10.23】游戏
- 2568. 【NOIP2011模拟9.17】地铁建设 (Standard IO)
- {题解}[jzoj2573]【NOIP2011模拟9.20】序列
- jzoj 3076. 【备战NOIP2012图论专项模拟试题】位图
- 【NOIP2015模拟10.20】ACM
- 2016.08.17【初中部 NOIP提高组 】模拟赛C(图论专项模拟试题)
- 纪中高中OJ3079. 【备战NOIP2012图论专项模拟试题】砍树题解
- JZOJ 5354. 【NOIP2017提高A组模拟9.9】导弹拦截
- PopupWindow进阶用法——android上实现类似UCweb的自定义menu,完全模拟系统事件