2022.7.11 模拟赛
2022 7.11 模拟赛#
比赛 link#
#
题意:
定义
给定 ,求
思路:
签到题
容易发现,当 为合数且 有两个不同质因子时,
其余时候 , 且
线性筛质数并更新就行了
时间复杂度
code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+1;
#define ll long long
#define int long long
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int cnt;
int p[7000000];
bool vis[N];
int can[N];
inline void prework(){
can[1]=1;
for(int i=2;i<N;++i){
can[i]=1;
if(!vis[i])
p[++cnt]=i,can[i]=i;
for(int j=1;j<=cnt&&i*p[j]<N;++j){
vis[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
for(int i=1;i<=cnt;++i)
for(ll j=p[i];j<N;j*=p[i]){
can[j]=p[i];
}
}
inline int solve(int n){
ll res=0;
for(int i=1;i<=n;++i)
res+=1ll*can[i];
return res;
}
signed main(){
prework();
int a=read(),b=read();
printf("%lld\n",solve(b)-solve(a-1));
}
注意 的时候会爆
不开 的下场:
包含#
题意:
定义 包含 :
给定一个有 个正整数 的集合 和 次询问
每次询问给你一个数 ,请回答 中是否存在一个数包含
思路:
第一想法:爆搜
暴力枚举并更新 可以包含的数,这样可以做到每次查询
时间复杂度
很显然不够优,考虑记忆化
若是一个数 且 所有包含的数已经更新过了,那么当搜 搜到 时就可以不用更新了
这样每个数最多只会被更新一次,保证了复杂度
时间复杂度
code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,m,f[N];
inline void dfs(int x,int now,int bit){
if(f[now]) return;
if(bit>=20){
f[now]=1;
return;
}
if((x>>bit)&1) dfs(x,now-(1<<bit),bit+1);
dfs(x,now,bit+1);
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;++i){
int x=read();
dfs(x,x,0);
}
for(int i=1;i<=m;++i){
int x=read();
puts(f[x]==1?"yes":"no");
}
}
考场上第一想法是 ,但最后写的还是爆搜
但为什么比别人的爆搜跑的都慢啊
最后只有
前缀#
题意:
牛牛有一个 串,串仅由 个小写英文字母组成,他现在将 串进行了无限次的复制扩展成了一个无线循环串。
例如一开始 "",那么牛牛就会将其变为" "
若某个字符串保留其原本字符出现的顺序,并且按照顺序取出若干个字符。可以不连续,可以不取。
我们称取出的这若干个字符连成的字符串为一个子序列。
若连续取出某个字符串的前 个字符,组成一个子串,我们称该字符串为原串长度为 的前缀。
对于一个字符串,若某字符串的至少一个子序列为 。则称它是一个“含 序列串”
牛牛想要知道对于给定的 ,他想要知道 的一个最短前缀满足它是一个“含 序列串”,它的长度有多长?
由于答案可能非常大,所以他要求你输出答案对 取余数后的结果即可。
特别的,如果 串不存在任何一个前缀满足他是一个“含 序列串”,请输出" "表示无解。
串中除了 个英文字母以外还会出现"",表示一个通配符。统配符可以视为任意字母。
例如循环 串为"$𝑎𝑏𝑐𝑎𝑏𝑐𝑎𝑏𝑐𝑎𝑏𝑐. . . 𝑎 ∗ 𝑐𝑎$$"时,最短含𝑡序列前缀长 。而当𝑡串为""时,最短含 序列前缀长 。
除此之外,牛牛输入的𝑡串还可能非常非常长,最长可以达到 这么长。
思路:
究极大模拟
还要高精
是真滴毒瘤啊
code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int N=1e5+5;
char S[N],t[N];
vector <int> K[27];
int T,id[N][2],c[N],len,ans;
inline void add(int &x,int y){
x+=y;
if(x>=mod) x-=mod;
}
inline int work(int l,int r,int C1,int C2){
int number=0,s=0,tot=0,pos;
for(int i=l;i<=r;++i)
c[i-l+1]=t[i]-'0';
for(pos=r-l+1;!c[pos];--pos);
--c[pos];
for(int i=pos+1;i<=r-l+1;++i)
c[i]=9;
for(int i=l;i<=r;++i,number=s%C1)
s=number*10+c[i-l+1],c[++tot]=s/C1;
s=0;
for(int i=tot;i;--i){
s+=c[i]*C2;
c[i]=s%10;
s/=10;
}
for(int i=1;i<=tot;++i)
s=(s*10+c[i])%mod;
add(ans,s);
return number;
}
signed main(){
scanf("%s",S);
len=strlen(S);
for(int i=0;i<len;++i)
K[S[i]^96].push_back(i),id[i][0]=K[S[i]^96].size()-1;
for(int i=0;i<len;++i)
K[0].push_back(i),id[i][1]=i;
cin>>T;
for(;T;--T){
scanf("%s",t);
int lent=strlen(t);
ans=0;
int l=0,r=0,beg=len-1,flag=1;
for(int f=0,now;l<lent;l=++r){
if(t[l]=='*') t[l]=96,f=1;
else f=0;
int G=t[l]^96,sz=K[G].size(),nxt;
if(!sz){
flag=0;
break;
}
if(l+1<lent&&isdigit(t[l+1]))
while(r+1<lent&&isdigit(t[r+1]))
++r;
if(K[G][sz-1]<=beg)
nxt=K[G][0];
else
nxt=*upper_bound(K[G].begin(),K[G].end(),beg);
if(beg<nxt) add(ans,nxt-beg);
else add(ans,len-beg+nxt);
beg=nxt;
if(l<r){
if(now=work(l+1,r,sz,len)){
nxt=K[G][(id[beg][f]+now)%sz];
if(beg<nxt) add(ans,nxt-beg);
else add(ans,len-beg+nxt);
beg=nxt;
}
}
}
if(!flag) puts("-1");
else printf("%d\n",ans);
}
return 0;
}
考场上没看,直接跳了
你没看到我题面都是直接复制的吗
移动#
题意:
共有 这 个闸门,它们分别处在 这 个点上
你要从 号点走到 号点
告诉你 次闸门 的开关操作, 会从 开始一直关到
若是在某一时刻 号闸门是关着的,那么你不能停在这
每次移到左边或右边的点,且需要花费 单位的时间
求最小需要花费多少时间
思路:
考场上乱搞了一个贪心,跑过了所有手造数据,因此直接交了
,code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
#define pb push_back
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,m,cnt;
int q[N];
bool vis[N];
struct node{
int s,e;
int id;
inline bool operator < (const node x) const{
return id+s==x.id+x.s?(id==x.id?e>x.e:id>x.id):id+x.s>x.id+s;
}
};
vector <node> p[N];
signed main(){
n=read(),m=read();
for(int i=1;i<=m;++i){
int x=read(),s=read(),e=read();
p[x].pb({s,e,x});
vis[x]=1;
}
for(int i=1;i<=n;++i)
if(!vis[i]) q[++cnt]=i;
q[++cnt]=n+1;
for(int i=1;i<=cnt;++i){
int a=q[i];
for(int j=q[i-1]+1;j<a;++j){
for(auto x:p[j]) p[a].pb(x);
p[j].clear();
}
sort(p[a].begin(),p[a].end());
}
int nowtime=0,nowpos=0;
for(int i=1;i<=cnt;++i){
int a=q[i];
for(auto x:p[a]){
int s=x.s,e=x.e,id=x.id;
if(id-nowpos>=s-nowtime)
if(e>nowtime) nowtime=e,nowpos=id-1;
else if(e==nowtime) nowpos=min(nowpos,id-1);
else{
nowtime+=q[i]-nowpos;
nowpos=q[i];
break;
}
}
if(nowpos!=q[i]){
nowtime+=q[i]-nowpos;
nowpos=q[i];
}
}
cout<<nowtime<<endl;
}
为什么这题分最高啊喂
正解是 ,但是用最短路维护
因为考虑一个点可以移动到左右两个点,所以整一个 记录最短时间并更新左右两个点
更新时需满足两个闸门同时开启
时间复杂度
code:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
const int inf=2e9;
#define pb push_back
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
struct pii{
int a,b;
inline bool operator < (const pii A) const{
return a==A.a?b<A.b:a<A.a;
}
};
vector <pii> v[N],cur;
int id[N],f[N];
int n,m;
struct pt{
int id,x,t;
};
inline bool operator > (pt a,pt b){
return a.t>b.t;
}
priority_queue <pt,vector <pt>,greater <pt> > p;
inline void cal(pt a,int x){
int r=v[a.x][a.id-id[a.x]].b;
int i=lower_bound(v[x].begin(),v[x].end(),(pii){a.t+1,0})-v[x].begin()-1;
if(v[x][i].b>=a.t+1&&f[id[x]+i]>a.t+1){
f[id[x]+i]=a.t+1;
p.push({id[x]+i,x,a.t+1});
}
++i;
for(;i<(int)v[x].size()&&v[x][i].a<=r+1;++i){
if(f[id[x]+i]>v[x][i].a){
f[id[x]+i]=v[x][i].a;
p.push({id[x]+i,x,v[x][i].a});
}
}
}
signed main(){
n=read(),m=read();
for(int i=1;i<=m;++i){
int x=read(),y=read(),z=read();
v[x].pb({y,z});
}
v[0].pb({0,inf});
v[n+1].pb({0,inf});
id[1]=1;
for(int i=1;i<=n;++i){
sort(v[i].begin(),v[i].end());
cur.clear();
int mx=-1;
for(auto x:v[i]){
if(x.a>mx+1) cur.pb({mx+1,x.a-1});
mx=max(mx,x.b);
}
cur.pb({mx+1,inf});
v[i]=cur;
id[i+1]=id[i]+v[i].size();
}
memset(f,0x3f,sizeof(f));
f[0]=0;
p.push({0,0,0});
while(!p.empty()){
auto x=p.top();
p.pop();
if(x.t>f[x.id]) continue;
if(x.x>0) cal(x,x.x-1);
if(x.x<=n) cal(x,x.x+1);
}
cout<<f[id[n+1]]<<endl;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现