8.8考试总结(NOIP模拟33)[Hunter·Defence·Connect]
无法逃避的是自我,而无法挽回的是过去。
前言
还算可以,不过 T1 少 \(\bmod\) 了一下挂了 25pts,T2 没看清题面挂了 27pts。
下回注意吧。。
T1 Hunter
解题思路
感觉正解不是很好想到,但是看题解就比较好看懂。。
1 号猎人死亡的轮数等于在 1 号之前死亡的猎人数 +1。
根据期望的 线性 性, 就等于每个猎人比 1 号猎人先死的概率和。
不难发现第 i 个猎人比 1 号猎人先死的概率是 \(\dfrac{W_{i}}{W_{1}+W_{i}}\)
上面的内容直接从官方题解摘过来了,实现没有任何难度。。
说一下记忆化搜索吧。。。
很明显 对于 \(n\le 10\) 的点一般的搜索就可以了。
对于 \(n\le 20\)的就需要记忆化了。
记忆化向下搜索的时候最好不要传一些概率那一类的东西,比较难把控。
对于下一层的概率最好在这一层就算好。。。
然后再特判一下 1 的情况就好了。
code
25pts DFS
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e5+10,M=1e6+10,mod=998244353;
int n,ans,inv[M],s[N],f[1<<21];
int ksm(int x,int y)
{
int tmp=1;
while(y)
{
if(y&1) tmp=tmp*x%mod;
x=x*x%mod;
y>>=1;
}
return tmp%mod;
}
void dfs(int sta,int round,int E)
{
if(!(sta&1)) return ;
ans=(ans+f[sta]*s[1]%mod*round%mod*E%mod)%mod;
for(int i=1;i<=n;i++)
if((sta>>i-1)&1)
dfs(sta^(1<<i-1),round+1,E*f[sta]%mod*s[i]%mod);
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
s[i]=read();
for(int i=1;i<(1<<n);i++)
{
int sum=0;
for(int j=1;j<=n;j++)
if((i>>j-1)&1)
sum=(sum+s[j])%mod;
f[i]=ksm(sum,mod-2);
}
dfs((1<<n)-1,1,1);
printf("%lld",ans);
return 0;
}
45pts 记忆化 DFS
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e5+10,M=1e6+10,mod=998244353;
int n,ans,inv[M],s[N],f[1<<21],dp[1<<21];
int ksm(int x,int y)
{
int tmp=1;
while(y)
{
if(y&1) tmp=tmp*x%mod;
x=x*x%mod;
y>>=1;
}
return tmp%mod;
}
int dfs(int sta,int round)
{
if(!(sta&1)) return 0;
if(dp[sta]) return dp[sta];
dp[sta]=(dp[sta]+f[sta]*s[1]%mod*round%mod)%mod;
for(int i=1;i<=n;i++)
if((sta>>i-1)&1)
dp[sta]=(dp[sta]+dfs(sta^(1<<i-1),round+1)*f[sta]%mod*s[i]%mod)%mod;
return dp[sta];
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
s[i]=read();
for(int i=1;i<(1<<n);i++)
{
int sum=0;
for(int j=1;j<=n;j++)
if((i>>j-1)&1)
sum=(sum+s[j])%mod;
f[i]=ksm(sum%mod,mod-2);
}
printf("%lld",dfs((1<<n)-1,1));
return 0;
}
正解
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int mod=998244353,N=1e5+10;
int n,ans,s[N];
int ksm(int x,int y)
{
int tmp=1;
while(y)
{
if(y&1) tmp=tmp*x%mod;
x=x*x%mod;
y>>=1;
}
return tmp%mod;
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
s[i]=read();
for(int i=2;i<=n;i++)
ans=(ans+s[i]*ksm((s[i]+s[1]%mod),mod-2)%mod)%mod;
printf("%lld",(ans+1)%mod);
return 0;
}
T2 Defence
解题思路
首先感谢出题人没有写太多一个节点有多个法术的测试点。
其次,抱怨一下题目描述不清楚。。。
非常像之前做过的玫瑰花精这道题。
主要维护 7 个值,(其实有一些没有用的,但也无伤大雅)。
最左边的 1 的坐标以及对应的最左侧的连续的 0 的长度。
同样的东西,在右边也维护一个类似的。
还有一个中间的最大区间的长度以及左右端点。
也就是下图所表示的。
剩下的比较难写的就是 push_up
函数了,别的还好。
然后就是线段树合并一系列的事情了。。。。
code
AC代码
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
#define ls tre[x].l
#define rs tre[x].r
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e5+10;
int n,m,q,ans[N],root[N],fa[N];
int tot=1,head[N],nxt[N],ver[N];
int all;
vector<int > p[N];
struct Segment_Tree
{
int l,r,lp,rp,lmx,rmx,llen,rlen,len;
}tre[N*80];
void push_up(int x,int l,int r)
{
if(!ls&&!rs) return ;
if(ls)
{
tre[x].lp=tre[ls].lp;
tre[x].llen=tre[ls].lp-l;
}
else
{
tre[x].lp=tre[rs].lp;
tre[x].llen=tre[rs].lp-l;
}
if(rs)
{
tre[x].rp=tre[rs].rp;
tre[x].rlen=r-tre[rs].rp;
}
else
{
tre[x].rp=tre[ls].rp;
tre[x].rlen=r-tre[ls].rp;
}
int len1=tre[ls].len,len2=tre[rs].len,len3=0;
if(ls&&rs) len3=tre[ls].rlen+tre[rs].llen;
if(len1>=max(len2,len3))
{
tre[x].len=len1;
tre[x].lmx=tre[ls].lmx;
tre[x].rmx=tre[ls].rmx;
}
else if(len2>=max(len1,len3))
{
tre[x].len=len2;
tre[x].lmx=tre[rs].lmx;
tre[x].rmx=tre[rs].rmx;
}
else
{
tre[x].len=len3;
tre[x].lmx=tre[ls].rp;
tre[x].rmx=tre[rs].lp;
}
}
void insert(int &x,int l,int r,int pos)
{
if(!x) x=++all;
if(l==r)
{
tre[x].lp=tre[x].rp=tre[x].lmx=tre[x].rmx=l;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) insert(ls,l,mid,pos);
else insert(rs,mid+1,r,pos);
push_up(x,l,r);
}
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=merge(ls,tre[y].l,l,mid);
rs=merge(rs,tre[y].r,mid+1,r);
push_up(x,l,r);
return x;
}
void add(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x)
{
if(p[x].size())
for(int i=0;i<p[x].size();i++)
insert(root[x],1,m,p[x][i]);
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
dfs(to);
root[x]=merge(root[x],root[to],1,m);
}
ans[x]=max(tre[root[x]].len,tre[root[x]].llen+tre[root[x]].rlen);
}
signed main()
{
n=read();
m=read();
q=read();
for(int i=1,x,y;i<n;i++)
{
x=read();
y=read();
add(x,y);
fa[y]=x;
}
for(int i=1,x,y;i<=q;i++)
{
x=read();
y=read();
p[x].push_back(y);
}
dfs(1);
for(int i=1;i<=n;i++)
{
if(!root[i]) printf("-1\n");
else printf("%lld\n",ans[i]);
}
return 0;
}
造数据必备
可以出来链的,菊花图的,满二叉树的。。
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int random(int l,int r)
{
return rand()%(r-l+1)+l;
}
signed main()
{
freopen("date.in","w",stdout);
srand(time(0));
int n=10,m=20,q=random(1,10),opt=random(1,3);
cout<<n<<' '<<m<<' '<<q<<endl;
if(opt==1) for(int i=2;i<=n;i++) cout<<(i+1)/2<<' '<<i<<endl;
else if(opt==2) for(int i=2;i<=n;i++) cout<<1<<' '<<i<<endl;
else for(int i=2;i<=n;i++) cout<<i-1<<' '<<i<<endl;
for(int i=1;i<=q;i++) cout<<random(1,n)<<' '<<random(1,m)<<endl;
return 0;
}
T3 Connect
解题思路
考场上想的是先跑一个最大生成树,然后对于 n 所在的子树上进行一些操作。
后来尽管算了一下时间复杂度小的离谱,但还是交了上去QAQ。
然后考完之后看了一眼题解:状压,这复杂度才对嘛。
后来下午讲题的时候 战神 拿出了他的 AC_Code。
然后瞥了一眼四周都在截图。。。(我也。。
\(f_{sta,i}\) 表示现在状态是 sta ,这个联通块(或者说是挂了一些东西的链)的结尾是 j 节点。
然后状态的转移就可以是,在这个链上再挂上一些联通块,或者在链的尾部新加入节点。
预处理出每一种联通块内部的边的总价值。
以及某一个联通块向联通块外面的某一个点的连边的总价值。
最后进行状压转移就好了。。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=16;
int n,m,cet[1<<N][N],edge[N][N],all[1<<N],f[1<<N][N];
signed main()
{
n=read();m=read();
for(int i=1,x,y,val;i<=m;i++)
{
x=read();y=read();val=read();
edge[x][y]=edge[y][x]=val;
}
for(int i=1;i<(1<<n);i++)
for(int j=1;j<=n;j++)
for(int k=j+1;k<=n;k++)
if((i>>j-1)&1 and (i>>k-1)&1)
all[i]+=edge[j][k];
for(int i=1;i<(1<<n);i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if((i>>j-1)&1 and !((i>>k-1)&1))
cet[i][k]+=edge[j][k];
memset(f,-1,sizeof(f));
f[1][1]=0;
for(int i=1;i<(1<<n);i++)
for(int j=1;j<=n;j++)
if(f[i][j]!=-1)
{
for(int k=1;k<=n;k++)
if(!((i>>k-1)&1) and edge[j][k])
f[i|(1<<k-1)][k]=max(f[i|(1<<k-1)][k],f[i][j]+edge[j][k]);
for(int k=((1<<n)-1)^i;k;k=(((1<<n)-1)^i)&(k-1))
f[i|k][j]=max(f[i|k][j],f[i][j]+all[k]+cet[k][j]);
}
printf("%lld",all[(1<<n)-1]-f[(1<<n)-1][n]);
return 0;
}
8.8考试总结(NOIP模拟33)[Hunter·Defence·Connect]的更多相关文章
- 2021.8.8考试总结[NOIP模拟33]
T1 Hunter 考场上一看期望直接状压拿了$45pts$跑了.结果正解只用$4$行? 把问题转化为一号猎人之前死的猎人数的期望加一. 期望的线性性. 对每个猎人$i$,$w_i+w_1$种情况中有 ...
- [考试总结]noip模拟33
连炸两场... 伤心... 第一个题目首先因为有期望坐镇,然后跳过... 然后第二个题目发现题目挺绕的,然后转化了一句话题意,然后..... \(\huge{\text{转化错了!!!!}}\) 然而 ...
- NOIP 模拟 $33\; \rm Defence$
题解 \(by\;zj\varphi\) 题意就是维护 \(\rm max\{01mx,01l+01r\}\) 就是最长连续的一段 \(0\),左右 \(0\) 区间的加和. 可以启发式合并,也可以直 ...
- noip模拟33[进阶啦啦啦]
noip模拟33 solutions 不知道该咋说,这场考试其实是我这三四场以来最最最最最顺心的一场了 为啥呢?因为我这回思考有很多结果,得到了脑袋的回复 就是你想了半个小时就有了一点点头绪,那感觉就 ...
- noip模拟33
\(\color{white}{\mathbb{失足而坠千里,翻覆而没百足,名之以:深渊}}\) 这场考试的时间分配非常不科学 开题试图想 \(t1\) 正解,一个半小时后还是只有暴力,特别惊慌失措 ...
- 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]
6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...
- 5.23考试总结(NOIP模拟2)
5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...
- 5.22考试总结(NOIP模拟1)
5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
随机推荐
- 第三方模块npm
npm介绍 npm 全名 node package manager node包管理工具,增删查改 如果npm操作太慢,可以安装npm镜像 npm的下载 比如全局下载一个jquery文件,全局下载的 ...
- @Autowired报错原因分析和4种解决方案!
上图的报错信息相信大部分程序员都遇到过,奇怪的是虽然代码报错,但丝毫不影响程序的正常执行,也就是虽然编译器 IDEA 报错,但程序却能正常的执行,那这其中的原因又是为何? 报错原因分析 报错的原因 ...
- 17、lnmp_php编译安装
17.1.FastCGI介绍: 1.什么是CGI: CGI的全称为"通用网关接口",为http服务器与其他机器上的程序服务通信交流的一种工具,CGI程序 必须运行在网络服务器上:传 ...
- .NET Core授权失败如何自定义响应信息?
前言 在.NET 5之前,当授权失败即403时无法很友好的自定义错误信息,以致于比如利用Vue获取到的是空响应,不能很好的处理实际业务,同时涉及到权限粒度控制到控制器.Action,也不能很好的获取对 ...
- MySql:Navicat 连接不上虚拟机上的mysql容器
1.问题显示 通过windows主机navicat连接虚拟的mysql时报如下错误. 2.问题原因 由于navicat版本的问题,出现连接失败的原因:mysql8 之前的版本中加密规则是mysql_n ...
- 其他:Git生成SSH、Git生成本地库、下载远程库代码 命令
1.安装Git Bash https://git-scm.com/downloads 2.鼠标右键git bash here 3.执行以下命令: ① cd ~/.ssh/ [如果没有对应的文 ...
- mysql日期时间处理
获得当前周的周一到周日 select subdate(curdate(),date_format(curdate(),'%w')-1)//获取当前日期在本周的周一 select subdate(c ...
- Parrot os 安装vmtools
1.更新源(这步个人觉得官方源还可以,没网上说的那么慢) vim /etc/apt/sources.list.d/parrot.list linux命令 ,按i进入修改模式,修改结束,之后先按esc, ...
- CG-CTF WxyVM2
一.原本以为要动调,因为出现了这个,函数太长,无法反编译 后面才知道这玩意可以在ida的配置文件里面去改,直接改成1024. 里面的MAXFUNSIZE改成1024,就可以反编译了,这个长度是超过这个 ...
- python log装饰器
def log(func): #将原函数对象的指定属性复制给包装函数对象, 默认有 module.name.doc,或者通过参数选择 @functools.wraps(func) def wrappe ...