\(T1\)魔法师

\(f(x)\)是各个数位之积,当\(f(x)\ne 0\),每一位只能是\(1\sim 9\),考虑数位积的质因数分解只能是\(2,3,5,7\)的形式,考虑对所有的\((a,b,c,d)\)计算满足\(f(x)=2^a\times 3^b\times 5^c\times 7^d\)的\(x\)的数量

这个东西考虑用数位\(dp\)求

\(f[i][0/1][a][b][c][d]\)表示当前已经处理到从高到低第\(i\)为,前\(i\)位的拆分为\(2^a\times 3^b\times 5^c\times 7^d\)的方案数

我们现在得到了\(g[a][b][c][d]\)即满足小于等于\(n\)的所有拆分方案

我们做一个\(Min\)卷积,求一下方案数即可

\(h[a][b][c][d]=\sum g[x_1][x_2][x_3][x_4]\times g[y_1][y_2][y_3][y_4][\min(x_1,y_1)=a,\min(x_2,y_2)=b,\min(x_3,y_3)=c,\min(x_4,y_4)=d]\)

这个过程可以用四维后缀和优化

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int la=60,lb=38,lc=25,ld=25,mod=998244353;
int dp[22][2][64][43][28][28],f[16][65][43][28][28];
ll Ans,n,k;
int sola(int x)
{
if(x==2) return 1;
if(x==4) return 2;
if(x==6) return 1;
if(x==8) return 3;
return 0;
}
int solb(int x)
{
if(x==3) return 1;
if(x==6) return 1;
if(x==9) return 2;
return 0;
}
int solc(int x)
{
if(x==5) return 1;
return 0;
}
int sold(int x)
{
if(x==7) return 1;
return 0;
}
void Init(ll num)
{
int cnt=0,wei[50];
while(num)
{
wei[++cnt]=num%10;
num/=10;
}
reverse(wei+1,wei+1+cnt);
dp[0][1][0][0][0][0]=1;
for(int i=1;i<=cnt;i++)
{
dp[i][0][0][0][0][0]=1;
for(int j=1;j<=9;j++)
{
int ja=sola(j),jb=solb(j),jc=solc(j),jd=sold(j);
for(int a=0;a+ja<=la;a++)
for(int b=0;b+jb<=lb;b++)
for(int c=0;c+jc<=lc;c++)
for(int d=0;d+jd<=ld;d++)
dp[i][0][a+ja][b+jb][c+jc][d+jd]=(1ll*dp[i][0][a+ja][b+jb][c+jc][d+jd]+1ll*dp[i-1][0][a][b][c][d])%mod;
}
for(int j=1,opt=(j==wei[i]);j<=wei[i];j++,opt=(j==wei[i]))
{
int ja=sola(j),jb=solb(j),jc=solc(j),jd=sold(j);
for(int a=0;a+ja<=la;a++)
for(int b=0;b+jb<=lb;b++)
for(int c=0;c+jc<=lc;c++)
for(int d=0;d+jd<=ld;d++)
dp[i][opt][a+ja][b+jb][c+jc][d+jd]=(1ll*dp[i][opt][a+ja][b+jb][c+jc][d+jd]+1ll*dp[i-1][1][a][b][c][d])%mod;
}
}
for(int i=0;i<16;i++)
for(int a=0;a<=la;a++)
for(int b=0;b<=lb;b++)
for(int c=0;c<=lc;c++)
for(int d=0;d<=ld;d++)
{
f[i][a][b][c][d]=(1ll*dp[cnt][0][a][b][c][d]+1ll*dp[cnt][1][a][b][c][d])%mod;
}
for(int i=0;i<16;i++) f[i][0][0][0][0]--;
}
signed main()
{
scanf("%lld%lld",&n,&k);
Init(n);
for(int i=0;i<16;i++)
{
if(i&1)
for(int a=la;a>=0;a--)
for(int b=lb;b>=0;b--)
for(int c=lc;c>=0;c--)
for(int d=ld;d>=0;d--)
f[i][a][b][c][d]=(1ll*f[i][a][b][c][d]+1ll*f[i][a+1][b][c][d])%mod;
if(i&2)
for(int a=la;a>=0;a--)
for(int b=lb;b>=0;b--)
for(int c=lc;c>=0;c--)
for(int d=ld;d>=0;d--)
f[i][a][b][c][d]=(1ll*f[i][a][b][c][d]+1ll*f[i][a][b+1][c][d])%mod;
if(i&4)
for(int a=la;a>=0;a--)
for(int b=lb;b>=0;b--)
for(int c=lc;c>=0;c--)
for(int d=ld;d>=0;d--)
f[i][a][b][c][d]=(1ll*f[i][a][b][c][d]+1ll*f[i][a][b][c+1][d])%mod;
if(i&8)
for(int a=la;a>=0;a--)
for(int b=lb;b>=0;b--)
for(int c=lc;c>=0;c--)
for(int d=ld;d>=0;d--)
f[i][a][b][c][d]=(1ll*f[i][a][b][c][d]+1ll*f[i][a][b][c][d+1])%mod;
}
for(ll i2=0,now2=k;now2;i2++,now2/=2)
for(ll i3=0,now3=now2;now3;i3++,now3/=3)
for(ll i5=0,now5=now3;now5;i5++,now5/=5)
for(ll i7=0,now7=now5,res=0;now7;i7++,now7/=7)
{
for(int i=0;i<16;i++)
for(int j=0;j<16;j++)
if(((i^15)|(j^15))==15) Ans=(1ll*Ans+1ll*f[i][i2+(i&1)][i3+((i&2)!=0)][i5+((i&4)!=0)][i7+((i&8)!=0)]*f[j][i2+(j&1)][i3+((j&2)!=0)][i5+((j&4)!=0)][i7+((j&8)!=0)]%mod)%mod;
}
cout<<Ans<<"\n";
}

\(T2\ Warrior\)

首先当 \(l\) 确定的时候,\(r\) 越大字典序越小,考虑尺取法,每次移动时候判断有多少字典序小,每次查询\(O(n\log n)\),总复杂度是\(O(n^2\log n)\)

考虑如何在线段树上查询,考虑完全包含进去的字典序必然大。

暴力尺取

#define Eternal_Battle ZXK
#include<bits/stdc++.h>
#define MAXN 1000005
using namespace std;
int w[MAXN],b[MAXN],tot,n,k;
map<int,int>mp;
namespace Seg
{
//支持动态插入值
//然后再这棵线段树上继续尺取找比他小的
#define ls (now<<1)
#define rs ((now<<1)|1)
struct Tr
{
int l,r,num;
bool del;
}tr[MAXN<<2];
void build(int now,int l,int r)
{
tr[now].l=l,tr[now].r=r;
if(l==r) return ;
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}
void push_up(int now)
{
tr[now].del=(tr[ls].del|tr[rs].del);
}
void change(int now,int poz,int k)
{
if(poz==0) return ;
if(tr[now].l==poz&&tr[now].r==poz)
{
tr[now].num+=k;
if(tr[now].num) tr[now].del=true;
else tr[now].del=false;
return ;
}
int mid=(tr[now].l+tr[now].r)>>1;
if(poz<=mid)change(ls,poz,k);
else change(rs,poz,k);
push_up(now);
}
bool query(int now)
{
if(tr[now].l==tr[now].r)
{
if(tr[now].num>0) return true;
return false;
}
if(tr[ls].del) return query(ls);
return query(rs);
}
}
int Min_num(int l,int r)
{
int res=0,i,j;
//计算比他小的
// cout<<"Sit: "<<l<<" "<<r<<"\n";
for(i=1,j=0;i<=n;i++)
{
while(Seg::query(1)&&j<=n)
{
Seg::change(1,w[++j],-1);
}
res+=(n-j+1);
// if(l==5&&r==30)cout<<"sol: "<<i<<" "<<j<<"\n";
Seg::change(1,w[i],1);
}
for(int poi=i;poi<=j;poi++)
{
Seg::change(1,w[poi],1);
}
// cout<<"res: "<<res<<"\n";
return res;
}
int bc[MAXN];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
b[i]=w[i];
}
sort(b+1,b+1+n);
for(int i=1;i<=n;i++)
{
if(!mp[b[i]]) mp[b[i]]=++tot,bc[tot]=b[i];
}
Seg::build(1,1,tot);
for(int i=1;i<=n;i++) w[i]=mp[w[i]];
for(int l=1,r=0;l<=n;l++)
{
//尺取,往右走直到字典序小于k
while(r<n)
{
Seg::change(1,w[++r],1);
if(Min_num(l,r)<k)
{
Seg::change(1,w[r--],-1);
break;
}
else if(Min_num(l,r)==k) break;
}
if(Min_num(l,r)==k)
{
// cout<<l<<" "<<r<<"\n";
map<int,int>t;
for(int i=l;i<=r;i++)
{
t[bc[w[i]]]++;
}
for(map<int,int>::iterator it=t.begin();it!=t.end();it++)
{
for(int i=1;i<=it->second;i++)
{
cout<<it->first<<" ";
}
}
exit(0);
}
Seg::change(1,w[l],-1);
if(Min_num(l+1,r)==k)
{
map<int,int>t;
for(int i=l+1;i<=r;i++)
{
t[bc[w[i]]]++;
}
for(map<int,int>::iterator it=t.begin();it!=t.end();it++)
{
for(int i=1;i<=it->second;i++)
{
cout<<it->first<<" ";
}
}
exit(0);
}
}
}

考虑在这个基础上加一些随机化,考虑每次随机一个位置,然后如果小于\(k\)的话,就把小于\(k\)的删去,更新一下\(k\),期望下\(O(\log n)\)只剩下一个,单次查询\(O(n\log n)\),总复杂度\(O(n\log^2 n)\)

#include<bits/stdc++.h>
#define rint register int
#define mid ((l+r)>>1)
#define ll long long
#define M 131072
using namespace std;
int Rand(int l,int r)
{
return rand()*rand()%(r-l+1)+l;
}
int T=256,n,k,s[1000001],L[1000001],R[1000001],lim[1000001];
int tr[1000001],cntr[1000001];
void build()
{
for(int i=1;i<=n;++i)
{
if(cntr[i]>0) tr[i+M]=1;
if(cntr[i]<0) tr[i+M]=-1;
if(cntr[i]==0) tr[i+M]=0;
}
for(int i=M-1;i>=1;--i) tr[i]=tr[i<<1]?tr[i<<1]:tr[i<<1|1];
}
void change(int p,int v)
{
int now=p+M;
cntr[p]+=v;
if(cntr[p]>0) tr[now]=1;
if(cntr[p]<0) tr[now]=-1;
if(cntr[p]==0) tr[now]=0;
p=now;
p=(p>>1);
while(p) tr[p]=tr[p<<1]?tr[p<<1]:tr[p<<1|1],p=(p>>1);
}
signed main()
{
double t=clock();
srand(20050323);
scanf("%d %d",&n,&k);
for(rint i=1;i<=n;++i) scanf("%d",&s[i]);
for(rint i=1;i<=n;++i) L[i]=i,R[i]=n;
while(clock()-t<=1400000&&T--)
{
ll now=0;
for(rint i=1;i<=n;++i) now+=R[i]-L[i]+1;
now=Rand(0,now-1);
for(rint i=1;i<=n;++i) cntr[i]=0;
rint nowl,nowr;
for(rint i=1;i<=n;++i)
{
if(L[i]>R[i]) continue;
if(now>=R[i]-L[i]+1) now-=R[i]-L[i]+1;
else
{
nowl=i,nowr=L[i]+now;
break;
}
}
for(rint i=nowl;i<=nowr;++i) ++cntr[s[i]];
build();
ll tot=0;
for(rint l=1,r=0;l<=n;++l)
{
while(r<=n&&(r<l-1||tr[1]>=0))
{
if(++r<=n)
{
change(s[r],-1);
}
}
tot+=n-r+1;
lim[l]=r-1;
change(s[l],1);
}
if(tot<k) for(rint i=1;i<=n;++i) R[i]=min(R[i],lim[i]);
else for(rint i=1;i<=n;++i) L[i]=max(L[i],lim[i]+1);
}
vector<int> res;
for(int i=1;i<=n;++i)
if(L[i]<=R[i])
{
for(rint j=i;j<=L[i];++j) res.push_back(s[j]);
sort(res.begin(),res.end());
for(rint i=0;i<res.size();++i) printf("%d ",res[i]);
exit(0);
}
}

\(T3\)最佳观影

考虑分成两种情况

一种是没有放人的行,另一种是已经放人的行,首先放人的行左右两边可以分开维护

我们每次需要查询人数\(\times\)右端点最小的,考虑用线段树维护一下到边界的人数,在满足条件里选一个最小的就好了,考虑维护二元组\((r,r+d)\),由于我们贡献是\(Mid-r+Mid-d\)

第一维建立线段树,第二维在叶子上维护一个堆,就是查区间最大了

#include<bits/stdc++.h>
using namespace std;
int n,k,x1;
struct node{
int x,y,z;
friend bool operator < (node a,node b)
{
if(a.z!=b.z) return a.z>b.z;
if(a.x!=b.x) return a.x>b.x;
return a.y>b.y;
}
}tr[600100];
priority_queue<node> q[150010];
void build(int x,int l,int r)
{
tr[x].x=0,tr[x].y=0,tr[x].z=1<<30;
if(l==r) return;
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
long long cal(int l,int r)
{
return 1ll*(l+r)*(r-l+1)>>1;
}
long long calc(node a,int b)
{
if((a.y<k&&a.y-b<0)||(a.y>k&&a.y+b>k+k))return 1ll<<60;
return 1ll*b*abs(a.x-k)+cal(abs(k-a.y),abs(k-a.y)+b-1);
}
long long calc(int a,int b)
{
if(!a||a==k+k)return 1ll<<60;
return 1ll*b*abs(a-k)+cal(1,b-1>>1)+cal(1,b>>1);
}
void ins(int x,int l,int r,int p,node v)
{
if(l==r)
{
q[l].push(v);
tr[x]=q[l].top();
return;
}
int mid=(l+r)>>1;
if(p<=mid) ins(x<<1,l,mid,p,v);
else ins(x<<1|1,mid+1,r,p,v);
tr[x]=max(tr[x<<1],tr[x<<1|1]);
}
void erase(int x,int l,int r,int pos)
{
if(l==r)
{
q[l].pop();
tr[x]=q[l].size()?q[l].top():(node){0,0,1<<30};
return;
}
int mid=(l+r)>>1;
if(pos<=mid) erase(x<<1,l,mid,pos);
else erase(x<<1|1,mid+1,r,pos);
tr[x]=max(tr[x<<1],tr[x<<1|1]); }
node query(int x,int l,int r,int pos)
{
if(l>=pos)
{
return tr[x];
}
int mid=(l+r)>>1;
if(pos>mid) return query(x<<1|1,mid+1,r,pos);
return max(query(x<<1,l,mid,pos),query(x<<1|1,mid+1,r,pos));
}
void slo(int a,int b)
{
cout<<a<<" "<<k-(b>>1)<<" "<<k+(b-1>>1)<<"\n";
if((b>>1)+1<k)
{
ins(1,1,k,k-1-(b>>1),(node){a,k-1-(b>>1),abs(a-k)+1+(b>>1)});
}
if((b-1>>1)+1<k)
{
ins(1,1,k,k-1-(b-1>>1),(node){a,k+1+(b-1>>1),abs(a-k)+1+(b-1>>1)});
}
}
int main()
{
scanf("%d%d%d",&n,&k,&x1);
k=(k+1)>>1;
build(1,1,k);
slo(k,x1);
int L=k-1,R=k+1;
for(int i=2,x;i<=n;i++)
{
scanf("%d",&x);
node now=x<=k?query(1,1,k,x):(node){0,0,1<<30};
if(calc(L,x)<=min(calc(now,x),calc(R,x)))
{
if(!L) cout<<"-1\n";
else slo(L--,x);
}
else
{
if(calc(R,x)<calc(now,x))
{
slo(R++,x);
}
else
{
// cout<<1<<endl;
if(now.y<k)
{
erase(1,1,k,now.y);
cout<<now.x<<" "<<now.y-x+1<<" "<<now.y<<"\n";
now.y-=x,now.z+=x;
if(now.y) ins(1,1,k,now.y,now);
}
else
{
erase(1,1,k,k+k-now.y);
cout<<now.x<<" "<<now.y<<" "<<now.y+x-1<<"\n";
now.y+=x,now.z+=x;
if(now.y<k+k) ins(1,1,k,k+k-now.y,now); }
}
}
}
}

6.11 NOI 模拟的更多相关文章

  1. 7.11 NOI模拟赛 qiqi20021026的T1 四个指针莫队 trie树

    LINK:qiqi20021026的T1 考场上只拿到了50分的\(nq\)暴力. 考虑一个区间和一个区间配对怎么做 二分图最大带权匹配复杂度太高. 先考虑LCS的问题 常见解决方法是后缀数组/tri ...

  2. 7.11 NOI模拟赛 graph 生成函数 dp 多项式

    LINK:graph HDU题库里的原题 没做过自闭. 考虑dp 设\(f_{i,j}\)表示前i个点构成j个联通块是树的方案数. 对于一次询问答案即为\(\sum_{j}f_{n,j}j^k\) 考 ...

  3. 9.11 myl模拟赛

    9.11 myl 模拟赛 100 + 100 + 0 第一题耗费了太多的时间,导致最后一题没有时间想,直接去写了暴力,而且出题人没有给暴力分.... Problem 1. superman [题目描述 ...

  4. 5.30 NOI 模拟

    $5.30\ NOI $模拟 高三大哥最后一次模拟考了,祝他们好运 \(T1\)装箱游戏 显然可以将四种字母之间的空缺当做状态枚举 那么这道题就很显然了 #include<bits/stdc++ ...

  5. 5.23 NOI 模拟

    $5.23\ NOI $模拟 \(T1\)简单的计算几何题 \(zjr:\)我当时没改,那么自己看题解吧 倒是有个简单的随机化方法(能获得\(72pts,\)正确性未知)\(:\) 随机两条切椭圆的平 ...

  6. 5.6 NOI模拟

    \(5.6\ NOI\)模拟 明天就母亲节了,给家里打了个电话(\(lj\ hsez\)断我电话的电,在宿舍打不了,只能用教练手机打了) 其实我不是很能看到自己的\(future,\)甚至看不到高三的 ...

  7. 5.4 NOI模拟

    \(5.4\ NOI\)模拟 \(T1\) 想到分讨,但是暴力输出一下方案之后有很多特别的情况要讨论,就弃了... 假设\(a\)是原序列,\(b\)是我们得到的序列 设\(i\)是最长公共前缀,\( ...

  8. 11.12模拟考T1(可持续优化)PS:神奇的东西

    1.数列操作   (array.pas/c/cpp) [问题描述] 现在有一个数列,最初包含0个数.现在要对数列操作n次,操作有3类. 1) a k,在数列的最后插入一个整数k 2) s 将最近插入的 ...

  9. NOI模拟赛 Day1

    [考完试不想说话系列] 他们都会做呢QAQ 我毛线也不会呢QAQ 悲伤ING 考试问题: 1.感觉不是很清醒,有点困╯﹏╰ 2.为啥总不按照计划来!!! 3.脑洞在哪里 4.把模拟赛当作真正的比赛,紧 ...

随机推荐

  1. Nacos源码系列—订阅机制的前因后果(下)

    点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 nacos,即可免费获取源码 事件发布 在上一节中我们讲解了在Noti ...

  2. 无线:NB-IoT

    一. NB总体网络架构 NB-IoT端到端系统架构如下图所示: 终端:UE(User Equipment),通过空口连接到基站(eNodeB(evolved Node B , E-UTRAN 基站)) ...

  3. python操作MySQL与MySQL补充

    目录 python操作MySQL 基本使用 SQL注入问题 二次确认 视图 触发器 事务 存储过程 函数 流程控制 索引 练习 python操作MySQL python中支持操作MySQL的模块很多, ...

  4. 《Mybatis 手撸专栏》第10章:使用策略模式,调用参数处理器

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你这代码写的,咋这么轴呢! 说到轴,让我想起初中上学时老师说的话:"你那脑 ...

  5. PostMan 快快走开, ApiFox 来了, ApiFox 强大的Api调用工具

    简介 为什么要用ApiFox呢, 一般现在程序员开发测试, 一般都是PostMan, PostWoman等Api调用工具, 我之前也是一直在用, 但是今天我发现了一款相比于Postman更加好用的工具 ...

  6. CSP J/S 初赛总结

    CSP J/S 初赛总结 2021/9/19 19:29 用官方答案估计 J 涂卡的时候唯一的一支 2B 铅笔坏了,只能用笔芯一个个涂 选择 \(-6\ pts\) 判断 \(-3\ pts\) 回答 ...

  7. springboot引入mybatis遇到的坑

      前边分享了springboot项目的创建及springboot项目的默认配置文件等,想温习的小伙伴可移步至文章末尾阅读,感谢.今天来分享下springboot引入mybatis框架的步骤,有小伙伴 ...

  8. 初步了解认识正则表达式(Regex)

    如果你感到这篇文章对您有所帮助,那请您给我一个免费的赞吧QWQ! 如果想要深入理解什么是正则表达式,请购买教材<形式语言与自动机>,相信学完它之后一定会让你更加理解正则表达式! 1.你的同 ...

  9. 1.3 操作系统的第三个功能——存储管理功能 -《zobolの操作系统学习札记》

    1.3 操作系统的第三个功能--存储管理功能 作者zobol:关于操作系统概论-存储管理功能,我给出下列问题: 目录 1.3 操作系统的第三个功能--存储管理功能 问1:操作系统的文件管理系统主要是负 ...

  10. SAP Web Dynpro-监视应用程序

    您可以使用ABAP监视器来监视Web Dynpro应用程序. 存储有关Web Dynpro应用程序的信息. 您可以使用T代码-RZ20查看此信息. 您可以在Web Dynpro ABAP监视器中查看以 ...