8.11考试总结(NOIP模拟36)[Dove 打扑克·Cicada 与排序·Cicada 拿衣服]
我会化作人间的风雨陪在你的身边
T1 Dove 打扑克
解题思路
考场上是想了一个树状数组维护的打法,但是竟然和 \(qn^2\) 的算法一样是 65pts
暴力就是对于每一次 2 询问重新建一下树状数组,进行计算。。
正解与暴力最大的区别就在于改变了枚举的东西
由枚举每一个堆的大小变为枚举牌堆大小,从同一大小或者不同大小堆的组合中计算答案。
大体思路就是维护一个 set 来保证堆的大小的有序。
同时开一个桶,维护不同大小的堆的个数,进行计算就好了。
在处理询问的时候直接双指针扫就好了。
分别记录当前扫到的点以及符合条件的边界。
code
65pts 树状数组
#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=3e5+10;
int n,m,fa[N],siz[N],top,sta[N];
bool vis[N];
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
struct BIT
{
int num[N];
void clear(){memset(num,0,sizeof(num));}
int lowbit(int x){return x&(-x);}
void insert(int x,int tmp)
{
for(int i=x;i<=n;i+=lowbit(i))
num[i]+=tmp;
}
int query(int x)
{
int sum=0;
for(int i=x;i;i-=lowbit(i))
sum+=num[i];
return sum;
}
}tre;
signed main()
{
n=read(); m=read();
for(int i=1;i<=n;i++)
{
fa[i]=i;siz[i]=1;
tre.insert(1,1);
}
while(m--)
{
int opt,x,y,sum=0;
opt=read();
if(opt==1)
{
x=read(); y=read();
int fx=find(x),fy=find(y);
if(fx==fy) continue;
siz[fx]+=siz[fy];
fa[fy]=fx;
continue;
}
x=read();
tre.clear();
top=0;
for(int i=1;i<=n;i++)
{
int tmp=find(i);
if(vis[tmp]) continue;
vis[tmp]=true;
sta[++top]=siz[tmp];
}
sort(sta+1,sta+top+1);
for(int i=1;i<=top;i++)
{
if(sta[i]-x>0)
sum+=tre.query(sta[i]-x);
tre.insert(sta[i],1);
}
for(int i=1;i<=n;i++)
vis[fa[find(i)]]=false;
printf("%lld\n",sum);
}
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 N=1e5+10;
int n,m,all,fa[N],siz[N],sum[N];
multiset<int> s;
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
signed main()
{
n=read(); m=read();
for(int i=1;i<=n;i++)
{
fa[i]=i;
siz[i]=1;
}
sum[1]=n; all=n;
s.insert(1);
while(m--)
{
int opt,x,y,tot,ans;
opt=read();
if(opt==1)
{
x=read(); y=read();
int fx=find(x),fy=find(y);
if(fx==fy) continue;
all--;
auto it1=s.find(siz[fx]);
auto it2=s.find(siz[fy]);
s.erase(it1);
if(siz[fx]!=siz[fy]) s.erase(it2);
sum[siz[fx]]--;
sum[siz[fy]]--;
if(sum[siz[fx]]) s.insert(siz[fx]);
if(siz[fx]!=siz[fy]&&sum[siz[fy]]) s.insert(siz[fy]);
fa[fy]=fx;
siz[fx]+=siz[fy];
if(!sum[siz[fx]]) s.insert(siz[fx]);
sum[siz[fx]]++;
continue;
}
x=read(); tot=all; ans=0;
auto l=s.begin(),r=s.begin();
for(l=s.begin();l!=s.end();l++)
{
while((*r)-(*l)<x&&r!=s.end()) tot-=sum[(*r)],r++;
if(r==s.end()) break;
if((*l)==(*r))
{
ans+=(sum[(*l)]-1)*sum[(*l)]/2;
tot-=sum[(*r)]; r++;
if(r==s.end()) continue;
}
ans+=sum[(*l)]*tot;
}
printf("%lld\n",ans);
}
return 0;
}
T2 Cicada 与排序
解题思路
学习了 cty 的打法后我直接拍手称赞。。
模拟归并排序的过程,并且枚举同一数值的数来自左边区间的个数。
计算这个是总共的相同数值的第几个的概率。
最后根据概率算出期望就好了。
代码轻度压行,自我感觉良好。。。(逃
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=510,mod=998244353;int n,jc[N],vjc[N],inv[N],ans[N],cnt,lsh[N];
struct Node{
int id,dat,p[N];
bool friend operator < (Node x,Node y){return x.dat<y.dat;}
}s[N],fb[N];
int ksm(int x,int y){
int temp=1;
while(y){
if(y&1) temp=temp*x%mod;
x=x*x%mod;y>>=1;
}return temp;
}
void init(){
jc[0]=inv[0]=vjc[0]=1;
for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod,inv[i]=inv[i-1]*2%mod;
vjc[n]=ksm(jc[n],mod-2); inv[n]=ksm(inv[n],mod-2);
for(int i=n-1;i>=1;i--) vjc[i]=vjc[i+1]*(i+1)%mod,inv[i]=inv[i+1]*2%mod;
sort(lsh+1,lsh+cnt+1); cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
for(int i=1;i<=n;i++) s[i].dat=lower_bound(lsh+1,lsh+cnt+1,s[i].dat)-lsh;
}
int C(int x,int y){if(y>x) return 0;return jc[x]*vjc[y]%mod*vjc[x-y]%mod;}
void merge(int l,int r){
if(l==r) return ;
int mid=(l+r)>>1,len=r-l+1,q[N][2];
merge(l,mid); merge(mid+1,r);
memcpy(fb+l,s+l,sizeof(Node)*len); memset(q,0,sizeof(q));
for(int i=l;i<=mid;i++)q[s[i].dat][0]++;
for(int i=mid+1;i<=r;i++)q[s[i].dat][1]++;
for(int i=l;i<=r;i++) for(int j=1;j<=n;j++)s[i].p[j]=0;
for(int i=l;i<=mid;i++){
if(!q[s[i].dat][0]||!q[s[i].dat][1]) continue;
for(int j=1;j<=q[s[i].dat][0];j++){
for(int k=1;k<=q[s[i].dat][1]+j-1;k++)s[i].p[k]=(s[i].p[k]+C(k-1,j-1)*fb[i].p[j]%mod*inv[k]%mod)%mod;
for(int k=q[s[i].dat][1];k<=q[s[i].dat][1]+j-1;k++)s[i].p[q[s[i].dat][1]+j]=(s[i].p[q[s[i].dat][1]+j]+C(k-1,q[s[i].dat][1]-1)*fb[i].p[j]%mod*inv[k]%mod)%mod;
}
}
for(int i=mid+1;i<=r;i++){
if(!q[s[i].dat][0]||!q[s[i].dat][1]) continue;
for(int j=1;j<=q[s[i].dat][1];j++){
for(int k=1;k<=q[s[i].dat][0]+j-1;k++)s[i].p[k]=(s[i].p[k]+C(k-1,j-1)*fb[i].p[j]%mod*inv[k]%mod)%mod;
for(int k=q[s[i].dat][0];k<=q[s[i].dat][0]+j-1;k++)s[i].p[q[s[i].dat][0]+j]=(s[i].p[q[s[i].dat][0]+j]+C(k-1,q[s[i].dat][0]-1)*fb[i].p[j]%mod*inv[k]%mod)%mod;
}
}
for(int i=l;i<=r;i++)for(int j=1;j<=n;j++)if(!s[i].p[j]) s[i].p[j]=fb[i].p[j];
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
lsh[++cnt]=s[i].dat=read();s[i].id=i;
for(int j=1;j<=n;j++)s[i].p[j]=1;
}
init();merge(1,n);sort(s+1,s+n+1);
for(int i=1;i<=n;i++){
int j=i; while(s[j+1].dat==s[i].dat) j++;
for(int k=i;k<=j;k++)for(int l=i;l<=j;l++)ans[s[k].id]=(ans[s[k].id]+l*s[k].p[l-i+1]%mod)%mod;i=j;
}
for(int i=1;i<=n;i++)printf("%lld ",ans[i]);
return 0;
}
T3 Cicada 拿衣服
题解
\(n^2\) 可以过 30000 的数据。。
我又用线段树手动套了一个 log 卡一卡范围就好了
(数据点分治) (雾
code
28pts 线段树
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
#define ls x<<1
#define rs x<<1|1
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=5e5+10,INF=1e18,base=2147483647;
int n,m,ans[N],s[N];
struct Segment_Tree
{
int mx,mn,ad,o;
}tre[N<<2];
void push_up(int x)
{
tre[x].ad=tre[ls].ad&tre[rs].ad;
tre[x].o=tre[ls].o|tre[rs].o;
tre[x].mn=min(tre[ls].mn,tre[rs].mn);
tre[x].mx=max(tre[ls].mx,tre[rs].mx);
}
void build(int x,int l,int r)
{
if(l==r)
{
tre[x].o=tre[x].mx=tre[x].mn=tre[x].ad=s[l];
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(x);
}
int query_min(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tre[x].mn;
int mid=(l+r)>>1,ans1=INF,ans2=INF;
if(L<=mid) ans1=query_min(ls,l,mid,L,R);
if(R>mid) ans2=query_min(rs,mid+1,r,L,R);
return min(ans1,ans2);
}
int query_max(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tre[x].mx;
int mid=(l+r)>>1,ans1=0,ans2=0;
if(L<=mid) ans1=query_max(ls,l,mid,L,R);
if(R>mid) ans2=query_max(rs,mid+1,r,L,R);
return max(ans1,ans2);
}
int query_or(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tre[x].o;
int mid=(l+r)>>1,ans1=0,ans2=0;
if(L<=mid) ans1=query_or(ls,l,mid,L,R);
if(R>mid) ans2=query_or(rs,mid+1,r,L,R);
return ans1|ans2;
}
int query_and(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tre[x].ad;
int mid=(l+r)>>1,ans1=base,ans2=base;
if(L<=mid) ans1=query_and(ls,l,mid,L,R);
if(R>mid) ans2=query_and(rs,mid+1,r,L,R);
return ans1&ans2;
}
signed main()
{
int sum=0;
n=read(); m=read();
for(int i=1;i<=n;i++)
s[i]=read();
build(1,1,n);
for(int len=n;len>=1;len--)
{
if(sum==n) break;
for(int l=1;l+len-1<=n;l++)
{
if(sum==n) break;
int r=l+len-1;
int mn=query_min(1,1,n,l,r);
int mx=query_max(1,1,n,l,r);
int o=query_or(1,1,n,l,r);
int ad=query_and(1,1,n,l,r);
int temp=mn+o-mx-ad;
if(temp>=m)
for(int i=l;i<=r;i++)
{
if(!ans[i]) sum++;
ans[i]=max(ans[i],r-l+1);
}
}
}
for(int i=1;i<=n;i++)
if(ans[i]) printf("%lld ",ans[i]);
else printf("%lld ",-1ll);
return 0;
}
正解
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
#define ls x<<1
#define rs x<<1|1
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=1e6+10,INF=1e18,base=2147483647;
int n,m,ans[N],s[N];
signed main()
{
int sum=0;
n=read(); m=read();
for(int i=1;i<=n;i++)
s[i]=read();
for(int l=1;l<=n;l++)
{
int pos=-1,maxn;
int mn=s[l],mx=s[l],o=s[l],ad=s[l];
if(mn+o-mx-ad>=m) pos=l;
maxn=mn+o-mx-ad;
for(int r=l+1;r<=n;r++)
{
mn=min(mn,s[r]);
mx=max(mx,s[r]);
o|=s[r];
ad&=s[r];
int temp=mn+o-mx-ad;
maxn=max(maxn,temp);
if(temp>=m) pos=r;
if(n<=30000) continue;
if(r-l+1>700) break;
}
if(pos==-1) continue;
for(int i=l;i<=pos;i++)
ans[i]=max(ans[i],pos-l+1);
}
for(int i=1;i<=n;i++)
if(ans[i]) printf("%lld ",ans[i]);
else printf("%lld ",-1ll);
return 0;
}
8.11考试总结(NOIP模拟36)[Dove 打扑克·Cicada 与排序·Cicada 拿衣服]的更多相关文章
- 2021.8.11考试总结[NOIP模拟36]
T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...
- 6.11考试总结(NOIP模拟7)
背景 时间分配与得分成反比,T1 20min 73pts,T2 1h 30pts,T3 2h 15pts(没有更新tot值,本来应该是40pts的,算是本次考试中最遗憾的地方了吧),改起来就是T3比较 ...
- 2021.10.11考试总结[NOIP模拟74]
T1 自然数 发现\(mex\)是单调不降的,很自然地想到用线段树维护区间端点的贡献. 枚举左端点,用线段树维护每个右端点形成区间的\(mex\)值.每次左端点右移相当于删去一个数. 记\(a_i\) ...
- 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 ...
- 「考试」noip模拟9,11,13
9.1 辣鸡 可以把答案分成 每个矩形内部连线 和 矩形之间的连线 两部分 前半部分即为\(2(w-1)(h-1)\),后半部分可以模拟求(就是讨论四种相邻的情况) 如果\(n^2\)选择暴力模拟是有 ...
- Noip模拟36 2021.8.11
刚题的习惯还是改不了,怎么办??? T1 Dove打扑克 考场上打的动态开点线段树+并查集,考后发现自己像一个傻子,并查集就行.. 这几天恶补数据结构疯了 用树状数组维护后缀和,$siz_i$表示编号 ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- [考试总结]noip模拟23
因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...
随机推荐
- javascript现代编程系列教程之五——正零和负零
在JavaScript中,正零(+0)和负零(-0)都代表数值0,它们在大多数情况下是等价的.然而,在某些特定的场景下,正零和负零的行为会有所不同. 除法操作:当0被用作除数时,正零和负零会产生不同的 ...
- 登录chatgpt的时候出现429的解决方法,亲测有效
登录chatgpt的时候出现429的解决方法 PS:在2023年3月14日晚还是可以用的,亲测有效 登录chatgpt的时候出现429的解决方法 很多时候在国内用代理进入chatgpt的时候会出现42 ...
- 第四課-Channel Study File Reader & File Writer
示例描述:从数据库中读取数据并过滤转换为HL7并存放到指定目录;然后读取目录中的HL7文件转换为txt文本并存放到指定目录. 首先在F:\MirthConnect\Test目录下创建Out目录存放输出 ...
- 力扣275(jav&python)-H 指数 II(中等)
题目: 给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数,citations 已经按照 升序排列 .计算并返回该研究者的 h 指数. h ...
- 暑期集训 Day5 —— 模拟赛复盘
${\color{Green} \mathrm{Problem\ 1 :选数 }} $ 签到题,一眼二分,但是打模板时死循环了: while(L<R){ int mid=(L+R)>> ...
- 揭秘远程证明架构EAA:机密容器安全部署的最后一环 | 龙蜥技术
简介:如果需要在云上 HW-TEE 环境里启动一个加密容器,如何在启动过程中获取容器的解密密钥? 文 / 周亮, 云原生机密计算 SIG 核心成员. 在云原生场景下,基于HW-TEE(如Inte ...
- 供应链商品域DDD实践
简介: DDD是一套方法论,实践能否成功,不仅仅是个技术问题,更是执行贯彻实施的问题.本文将就DDD的基本概念和DDD的实施进行分享. 作者 | 侧帽来源 | 阿里技术公众号 前言 供应链商品域DDD ...
- WPF 已知问题 RadioButton 指定 GroupName 后关闭窗口可能导致无法选中
本文记录一个 WPF 已知问题,当 WPF 的 RadioButton 指定 GroupName 且将 IsChecked 状态绑定到 ViewModel 上,将包含以上控件的代码的窗口显示两个,接着 ...
- 2019-8-31-C#-简单读取文件
title author date CreateTime categories C# 简单读取文件 lindexi 2019-08-31 16:55:58 +0800 2018-07-19 16:48 ...
- k8s修改iptables模式变成ipvs
环境:https://www.cnblogs.com/yangmeichong/p/16477200.html 一.修改 iptables 变成 ipvs 模式 ipvs 采用的 hash 表,ipt ...