NOIP模拟62
T1 Set
解题思路
抽屉原理
发现对于前缀和向 \(n\) 取模之后一定是右两个值相等的(包括什么都不选的 0 )。
假设 \(pre_j=pre_i\) 那么 \([j+1,i]\) 之间这一段数字的和一定是 \(n\) 的倍数。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<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=1e6+10,M=1e3+10;
int n,m,s[N],pre[N],las[N];
signed main()
{
freopen("a.in","r",stdin); freopen("a.out","w",stdout);
memset(las,-1,sizeof(las)); n=read(); las[0]=0;
for(int i=1;i<=n;i++)
{
s[i]=read()%n;
pre[i]=(pre[i-1]+s[i])%n;
if(las[pre[i]]!=-1)
{
printf("%lld\n",i-las[pre[i]]);
for(int j=las[pre[i]]+1;j<=i;j++)
printf("%lld ",j);
exit(0);
}
las[pre[i]]=i;
}
return 0;
}
T2 Read
解题思路
发现内存限制了我们的想象(其实我考场上看错题了。。)
发现对于有一种书的个数大于其他书的个数之和 +1 答案才不是 0 。
因此,可以 \(n\) 的复杂度扫一遍,用两个变量id, cnt, cnt 初始为0。
然后生成每一个 \(A_i\) , 如果 \(cnt=0\) , 那么就令 \(id=A[i],cnt=1\) , 否则如果 \(id==A[i]\) , 则 \(cnt++\) , 如果不等于, \(cnt--\) 。
最后只要再扫一遍求出id 的出现次数即可。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<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=5e7+10,Mx=1e3+10;
int M,K,n,all,cnt,id,Num[Mx],X[Mx],Y[Mx],Z[Mx];
void init()
{
M=read(); K=read();
for(int i=1;i<=M;i++) Num[i]=read(),n+=Num[i];;
for(int i=1;i<=M;i++) X[i]=read();
for(int i=1;i<=M;i++) Y[i]=read();
for(int i=1;i<=M;i++) Z[i]=read();
int S=(1<<K)-1,len=0;
for(int i=1,temp;i<=M;i++)
{
temp=X[i]; int las=X[i];
if(!cnt) id=temp,cnt=1;
else if(id==temp) cnt++;
else cnt--;
for(int j=1;j<Num[i];j++)
{
las=(las*Y[i]+Z[i])&S;
temp=las;
if(!cnt) id=temp,cnt=1;
else if(id==temp) cnt++;
else cnt--;
}
}
}
void work()
{
int S=(1<<K)-1,len=0;
for(int i=1,temp;i<=M;i++)
{
temp=X[i]; int las=X[i]; all+=(temp==id);
for(int j=1;j<Num[i];j++)
{
las=(las*Y[i]+Z[i])&S;
temp=las; all+=(temp==id);
}
}
}
signed main()
{
freopen("b.in","r",stdin); freopen("b.out","w",stdout);
init(); work(); printf("%lld",(all<=(n+1)/2)?0:all-(n-all)-1);
return 0;
}
T3 题目交流通道
解题思路
好像是个容斥经典题(尽管我不会)。。
对于每一个距离为 0 的联通块给缩起来,称为团。
两个团之间的点的距离是一定的,那么就要考虑重边的情况,假设有 \(a\) 条边重复,如果存在 \(k\) 使得 \(d_{i,j}=d_{i,k}+d_{j,k}\) ,那么剩下所有的边只要大于等于 \(d_{i,j}\) 就可以了,方案数是 \((K-d_{i,j}+1)^a\)
如果不存在的话至少有一条边要等于 \(d_{i,j}\) 就好了,所以在上述情况的方案数中除去都是 大于 \(d_{i,j}\) 的情况,也就是 \((K-d_{i,j}+1)^a-(K-d_{i,j})^a\)
考虑处理团内部的边,然后经典的容斥就来了: \(f_i\) 表示 \(i\) 个点距离为 0 的方案数, \(g_i\) 表示不管是否合法 \(i\) 个点的图的方案数。
就有 \(g_i=(K+1)^{\binom{i}{2}}\) 也就是取值的边数次方。
\]
那么为什么组合系数是 \(\binom{i-1}{j-1}\) 呢,枚举时我们把图分成了两个部分:已知合法的和未知的。
那么显然未知的部分包含了一部分合法的团,为了防止重复,我们钦定枚举的是 1 节点(也可以钦定别的节点)所在的团是合法的部分,这样就相当于是从 \(i-1\) 个点中选择 \(j-1\) 个点与 1 节点联通。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<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=410,mod=998244353;
int n,m,ans=1,siz[N],fac[N],ifac[N],dis[N][N],f[N],g[N],fa[N];
int find(int x){if(fa[x]==x) return x;return fa[x]=find(fa[x]);}
int C(int x,int y,int p=mod){return fac[x]*ifac[y]%p*ifac[x-y]%p;}
int power(int x,int y,int p=mod){int temp=1;while(y){if(y&1) temp=temp*x%p;x=x*x%p;y>>=1;}return temp;}
signed main()
{
freopen("c.in","r",stdin); freopen("c.out","w",stdout);
n=read(); m=read();
fac[0]=ifac[0]=1; for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod,g[i]=f[i]=power(m+1,i*(i-1)/2),fa[i]=i;
ifac[n]=power(fac[n],mod-2); for(int i=n-1;i>=1;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=read();
for(int i=1;i<=n;i++) if(dis[i][i]) printf("0"),exit(0);
for(int i=1;i<=n;i++) for(int j=1;j<i;j++) if(dis[i][j]!=dis[j][i]||dis[i][j]>m) printf("0"),exit(0);
for(int i=1;i<=n;i++) for(int j=1;j<i;j++) for(int k=1;k<=n;k++) if(dis[i][k]+dis[k][j]<dis[i][j]) printf("0"),exit(0);
for(int i=1;i<=n;i++) for(int j=1;j<i;j++) f[i]=(f[i]-f[j]*g[i-j]%mod*C(i-1,j-1)%mod*power(m,j*(i-j))%mod+mod)%mod;
for(int i=1;i<=n;i++) for(int j=1;j<i;j++) if(!dis[i][j]&&find(i)!=find(j)) fa[find(i)]=find(j);
for(int i=1;i<=n;i++) siz[find(i)]++;
for(int i=1;i<=n;i++) if(find(i)==i) ans=ans*f[siz[i]]%mod;
for(int i=1;i<=n;i++)
for(int j=1,k;j<i;j++)
if(find(i)==i&&find(j)==j)
{
for(k=1;k<=n;k++) if(dis[i][k]&&dis[k][j]&&dis[i][k]+dis[k][j]==dis[i][j]) break;
if(k<=n) ans=ans*power(m-dis[i][j]+1,siz[i]*siz[j])%mod;
else ans=ans*(power(m-dis[i][j]+1,siz[i]*siz[j])-power(m-dis[i][j],siz[i]*siz[j]))%mod;
}
printf("%lld",ans);
return 0;
}
T4 题目难度提升
解题思路
貌似我的做法被 Hack 了(OJ 可以过就行。。),大概是细节处理不到位吧。
其实就是题解的做法,有了那两个思想时候我们就可以开两个 set 维护已经加入的数字以及剩下的数字。
加入我们需要查询 \((m,k)\) 之间是否有数字被放进去,可以直接在维护放入数字的 set 中查找第一个大于 \(m\) 数字,看他与 \(k\) 的大小关系。
对于每一次中位数的维护可以维护中间的两个数字什么然后就没啥了。。。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<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,INF=1e18;
int n,cnt,ans[N];
double mid,s[N];
bool flag;
multiset<double> se,in;
void solve1(int i)
{
double num=(*se.upper_bound(mid)),temp=*in.upper_bound(mid),r=2*num-mid;
if(temp<num) ans[i]=(*se.rbegin()),mid=(mid+temp)/2.0;
else if(temp<=r) ans[i]=(*se.rbegin()),mid=(mid+temp)/2.0;
else ans[i]=(*(--se.upper_bound(r))),mid=(mid+1.0*ans[i])/2.0;
se.erase(se.find(ans[i])); in.insert(ans[i]);
}
void solve2(int i)
{
double num=*se.lower_bound(mid),temp=*in.upper_bound(mid);
if(temp<num) ans[i]=(*se.rbegin()),mid=temp;
else ans[i]=num,mid=num;
se.erase(se.find(ans[i])); in.insert(ans[i]);
}
void solve()
{
mid=ans[1]=(*se.begin()); se.erase(se.find(ans[1]));
in.insert(s[1]); in.insert(INF);
for(int i=2;i<=n;i++)if(i&1) solve2(i); else solve1(i);
for(int i=1;i<=n;i++) printf("%lld ",ans[i]); exit(0);
}
signed main()
{
freopen("d.in","r",stdin); freopen("d.out","w",stdout);
n=read(); for(int i=1;i<=n;i++) s[i]=read(),se.insert(s[i]);
sort(s+1,s+n+1);
for(int i=2;i<=n;i++) if(s[i]==s[i-1]){flag=true;break;}
if(!flag) solve();
if(n&1) mid=s[n/2+1];
else mid=(1.0*s[n/2]+1.0*s[n/2+1])/2.0;
int pos=upper_bound(s+1,s+n+1,mid)-s-1,r,poi=n,i;
for(int i=2;i<=pos;i++) if(s[i]==s[i-1]){flag=false;break;}
if(flag) solve();
for(int i=pos-1;i>=1;i--)if(s[i]==s[i+1]){r=s[i];pos=i-1;break;}
in.insert(r); in.insert(r); in.insert(INF); mid=r;
se.erase(se.find(r)); se.erase(se.find(r));
ans[++cnt]=r; ans[++cnt]=r;
for(i=pos;i>=1&&poi>pos+2;i--)
{
ans[++cnt]=s[poi]; ans[++cnt]=s[i];
se.erase(se.find(s[i])); se.erase(se.find(s[poi]));
in.insert(s[i]); in.insert(s[poi]);
poi--;
}
while(cnt<n) pos=*se.rbegin(),ans[++cnt]=pos,in.insert(pos),se.erase(se.find(pos));
for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
return 0;
}
NOIP模拟62的更多相关文章
- Noip模拟62 2021.9.26
T1 Set 真就随机化拿了$90$?? 不过还是有依据的,毕竟这道题出解的几率很大,随出答案的概率也极大 所以不妨打一个随机化 1 #include<bits/stdc++.h> 2 # ...
- 2021.9.26考试总结[NOIP模拟62]
T1 set 从\(0\)到\(n\)前缀余数有\(n+1\)个,但只有\(n\)种取值,找到一样的两个输出区间即可. \(code:\) T1 #include<bits/stdc++.h&g ...
- NOIP模拟17.9.22
NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥
- NOIP 模拟4 T2
本题属于二和一问题 子问题相互对称 考虑对于问题一:知a求b 那么根据b数组定义式 显然能发现问题在于如何求dis(最短路) 有很多算法可供选择 dijsktra,floyed,bfs/dfs,spf ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- NOIP模拟赛20161022
NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...
- contesthunter暑假NOIP模拟赛第一场题解
contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...
- NOIP模拟赛 by hzwer
2015年10月04日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...
- 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...
随机推荐
- 重新整理.net core 计1400篇[三] (.net core 如何源代码调试和查看源码 )
前言 本来这里是写源代码的,因为vs没有那么容易调试查看到源代码,所以先把调试源代码和查看源代码弄完. 正文 需要修改一些vs配置,这个vs也是有要求的,要vs2017. 那么你还需要加载远程符号. ...
- redis 一百二十篇(历史发展)之第二篇
正文 简介: Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化, ...
- Sarsa模型和Q_learning模型简记
1. Sarsa模型 1.1 Sarsa类代码: class SarsaAgent(object): def __init__(self,state_n,action_n,learning_rate= ...
- SSM整合项目中使用百度Ueditor遇到的问题。
问题描述:无法上传图片,提示配置项加载有问题 大致情形:直接下载的ue编辑器,放在了/resources/ 目录下,也就是静态资源路径,然后更改web.xml,将tomcat默认拦截器配置放到所有 ...
- 《领域驱动设计》:从领域视角深入仓储(Repository)的设计和实现
简介: <领域驱动设计>中的Repository(下面将用仓储表示)层实际上是极具有挑战性的,对于它的理解,也十分重要.本文讲大部分内容都在众多前辈理论基础上,从一个崭新的领域视觉开始探索 ...
- 10种编程语言实现Y组合子
简介: Y组合子是Lambda演算的一部分,也是函数式编程的理论基础.它是一种方法/技巧,在没有赋值语句的前提下定义递归的匿名函数,即仅仅通过Lambda表达式这个最基本的"原子" ...
- 应对 Job 场景,Serverless 如何帮助企业便捷上云
简介:函数计算作为事件驱动的全托管计算服务,其执行模式天生就与这类 Job 场景非常契合,对上述痛点进行了全方面的支持,助力"任务"的无服务器上云. 作者:冯一博 任务(Jobs) ...
- 21.3K star!推荐一款可视化自动化测试/爬虫/数据采集神器!功能免费且强大!
大家好,我是狂师! 在大数据时代,信息的获取与分析变得尤为重要.对于开发者.数据分析师乃至非技术人员来说,能够高效地采集网络数据并进行分析是一个强有力的工具.今天,我要向大家推荐的是一款功能强大.操作 ...
- WPF 开源二维绘画小工具 GeometryToolDemo 项目
这是一个演示 WPF 进行二维绘画的小工具 Demo 项目,基于 MIT 协议在 GitHub 上完全开源 源作者是 YuWeiCong 我只是帮助开源的工具人 软件运行界面效果: 开源地址: htt ...
- Git基础使用指南-命令详解
Software is like sex: it's better when it's free. -- Linus Torvalds 前情须知 -O- 工作流程 首先要明确的是Git的工作流程,你使 ...