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\) 的总结写了吧.. 俗话说:" ...
随机推荐
- 我自己的JdbcTemplate
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import jav ...
- nuxt使用介绍[学习记录]
服务端渲染 传统服务端渲染 单页面应用 SPA nuxt 是什么 Nuxt.js 是一个基于 Vue.js 的通用应用框架. 通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 ...
- 【笔记】join using&AVG
oracle using 在oracle中,using用于简化连接查询,只有当查询是等值连接和连接中的列必须具有相同的名称与数据类型时,才能使用using关键字进行简化 比如原来是 select s. ...
- 剑指offer42(Java)-连续子数组的最大和(简单)
题目: 输入一个整型数组,数组中的一个或连续多个整数组成一个子数组.求所有子数组的和的最大值. 要求时间复杂度为O(n). 示例1: 输入: nums = [-2,1,-3,4,-1,2,1,-5,4 ...
- 力扣1668(java&python)-最大重复子字符串(简单)
题目: 给你一个字符串 sequence ,如果字符串 word 连续重复 k 次形成的字符串是 sequence 的一个子字符串,那么单词 word 的 重复值为 k .单词 word 的 最大重复 ...
- 力扣592(java)-分数加减运算(中等)
题目: 给定一个表示分数加减运算的字符串 expression ,你需要返回一个字符串形式的计算结果. 这个结果应该是不可约分的分数,即最简分数. 如果最终结果是一个整数,例如 2,你需要将它转换成分 ...
- Helm Chart 多环境、多集群交付实践,透视资源拓扑和差异
简介: 在本文中,我们将介绍如何通过 KubeVela解决多集群环境下 Helm Chart 的部署问题.如果你手里没有多集群也不要紧,我们将介绍一种仅依赖于 Docker 或者 Linux 系统的轻 ...
- 疫情带火了这款APP:2600个学生一天点赞70万次
这几天,全国中小学生经历了"过山车"一样的心情. 因为疫情的不断蔓延,1月27日,教育部下发通知,2020年春季学期延期开学. 随后,教育部又提出"利用网络平台,停课 ...
- 技术干货 | mPaaS 小程序高玩带你起飞:客户端预置小程序无视网络质量
简介: 弱网拉包无障碍,深度提升用户体验 传统的小程序技术容易受到网络环境影响,当网络质量不佳时可能导致拉取不到小程序包的情况.通过预置小程序,即可规避该问题.本文介绍了预置小程序的原理和预置小程序的 ...
- 阿里云云效发布研发协同工具,以新的产研协同工作方式助力实现BizDevOps
简介:2021云栖大会云效BizDevOps分论坛上,阿里云云效技术负责人陈鑫发布阿里云云效产品研发协同工具支撑ALPD理论,以新的产研协同工作方式助力实现BizDevOps. 编者按:10月21日 ...