abc 234
D - Prefix K-th Max
给出一个排列 \(p\) 和一个正整数 \(k\) ,对于所有的 \(i=k,k+1,\cdots,n\) ,需要找到 \(p\) 的前 \(i\) 个数中第 \(k\) 大的.
\(1\leq k\leq n\leq 5\cdot 10^5\)
建立线段树,之后就是单点修改和线段树上二分. 也可以 bit 上上二分.
时间复杂度 : \(O(n\log n)\)
空间复杂度 : \(O(n)\)
code
#include<bits/stdc++.h>
using namespace std;
char in[100005];
int iiter=0,llen=0;
inline char get(){
if(iiter==llen)llen=fread(in,1,100000,stdin),iiter=0;
if(llen==0)return EOF;
return in[iiter++];
}
inline int rd(){
char ch=get();while(ch<'0'||ch>'9')ch=get();
int res=0;while(ch>='0'&&ch<='9')res=(res<<3)+(res<<1)+ch-'0',ch=get();
return res;
}
inline void pr(int res){
if(res==0){putchar('0');return;}
static int out[10];int len=0;
while(res)out[len++]=res%10,res/=10;
for(int i=len-1;i>=0;i--)putchar(out[i]+'0');
}
const int N=5e5+10;
class seg_tree{
public:
int ts[N<<2];
void init(){memset(ts,0,sizeof(ts));}
void upd(int x,int l,int r,int pos){
if(l==r){ts[x]++;return;}
int mid=(l+r)>>1;
if(pos<=mid)upd(x<<1,l,mid,pos);
else upd(x<<1|1,mid+1,r,pos);
ts[x]=ts[x<<1]+ts[x<<1|1];
}
int qry(int x,int l,int r,int k){
if(l==r)return l;
int mid=(l+r)>>1;
if(k<=ts[x<<1|1])return qry(x<<1|1,mid+1,r,k);
else return qry(x<<1,l,mid,k-ts[x<<1|1]);
}
}T;
int n,k,a[N];
int main(){
n=rd();k=rd();
for(int i=0;i<n;i++)a[i]=rd()-1;
for(int i=0;i<n;i++){
T.upd(1,0,n-1,a[i]);
if(i>=k-1)pr(T.qry(1,0,n-1,k)+1),putchar('\n');
}
return 0;
}
/*inline? ll or int? size? min max?*/
E - Arithmetic Number
定义 \(\texttt{luck number}\) 是 \(d_1-d_2=d_3-d_2=\cdots =d_{k}-d_{k-1}\) 的数 .
给出一个数 \(X\) ,求不小于 \(X\) 的最小的 \(\texttt{luck number}\) .
\(1\leq X\leq 10^{17}\)
小于 \(10^6\) 的暴力跑.
其余考虑,如果 \(d_1\) 和 \(d_2\) 确定了,那么后面的都可以确定了,那么枚举 \(d_2\) 从 \(X_2\) 到 \(9\) , 依次 check .
其余的确定 \(d_1=X_1+1\) ,枚举 \(d_2\) 从 \(0\) 到 \(9\) ,依次 check .
这里我写错了一个点,很久没有调出来,就是检查的时候不是直接地判断 \(tmp<X_i\) ,而是之前如果出现了 \(tmp>X_i\) ,那么之后都是当前数必定大于 \(X\) ,不管后面如何.
时间复杂度 : \(O(|X|)\)
空间复杂度 : \(O(|X|)\)
code
#include<bits/stdc++.h>
using namespace std;
string s;
bool chk(int val){
vector<int>v;
while(val){
v.push_back(val%10);
val/=10;
}
if((int)v.size()<=2)return true;
int dif=v[1]-v[0];
for(int i=2;i<(int)v.size();i++)if(v[i]-v[i-1]!=dif)return false;
return true;
}
void work1(){
int val=0;
for(int i=0;i<(int)s.size();i++)val=val*10+s[i]-'0';
for(int i=val;;i++){
if(chk(i)){
cout<<i<<endl;
return;
}
}
}
void work2(){
vector<int>v;
for(int i=0;i<(int)s.size();i++)v.push_back(s[i]-'0');
int dif=v[1]-v[0],tmp=v[1];
bool ok=true,large=false;
for(int i=2;i<(int)v.size();i++){
tmp+=dif;
if(tmp<0||tmp>9||(tmp<v[i]&&!large))ok=false;
if(tmp>v[i])large=true;
}
if(ok){
cout<<v[0]<<v[1];
tmp=v[1];
for(int i=2;i<(int)v.size();i++){
tmp+=dif;
cout<<tmp;
}
cout<<endl;
return;
}
for(int d=v[1]+1;d<10;d++){
dif=d-v[0];tmp=d;ok=true;
for(int i=2;i<(int)v.size();i++){
tmp+=dif;
if(tmp<0||tmp>9)ok=false;
}
if(ok){
tmp=d;
cout<<v[0]<<d;
for(int i=2;i<(int)v.size();i++){
tmp+=dif;
cout<<tmp;
}
cout<<endl;
return;
}
}
for(int d=0;d<10;d++){
dif=d-v[0]-1;tmp=d;ok=true;
for(int i=2;i<(int)v.size();i++){
tmp+=dif;
if(tmp<0||tmp>9)ok=false;
}
if(ok){
tmp=d;
cout<<v[0]+1<<d;
for(int i=2;i<(int)v.size();i++){
tmp+=dif;
cout<<tmp;
}
cout<<endl;
return;
}
}
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>s;
if((int)s.size()<6)work1();
else work2();
return 0;
}
/*inline? ll or int? size? min max?*/
F - Reordering
给出字符串 \(S\) . 问 \(S\) 中的子序列可以重排组成的字符串的个数. 模 \(998244353\).
\(1\leq |S|\leq 5000\)
直接 \(dp\) 即可 .
用 \(dp(i,j)\) 表示,到了字符 i 子序列长度为 \(j\) 的方案数.
code
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+10;
const int mod=998244353;
string s;
int C[N][N];
int cnt[N];
int dp[30][N];
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
C[0][0]=1;
for(int i=1;i<N;i++){
C[i][0]=1;
for(int j=1;j<N;j++){
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
}
cin>>s;
for(int i=0;i<(int)s.size();i++)cnt[s[i]-'a']++;
dp[0][0]=1;
for(int i=0;i<26;i++)for(int j=0;j<=(int)s.size();j++){
if(dp[i][j]==0)continue;
for(int k=0;k<=cnt[i];k++){
dp[i+1][j+k]=(dp[i+1][j+k]+1ll*dp[i][j]*C[j+k][k]%mod)%mod;
}
}
int ans=0;
for(int i=1;i<=(int)s.size();i++)ans=(ans+dp[26][i])%mod;
cout<<ans<<endl;
return 0;
}
/*inline? ll or int? size? min max?*/
G - Divide a Sequence
给出一个序列 \(A\) .
将序列分成几段,将当前分段的价值记为每一段的最大值减最小值的乘积 .
求所有分段价值的和 .
\(1\leq n\leq 3\cdot 10^5,1\leq A_i\leq 10^9\)
用 \(dp(i)\) 表示以 \(A_i\) 结尾的价值和 .
\(dp(i)=\sum dp(j)\max\{A_{j+1},A_{j+2},\cdots,A_i\}-\sum dp(j)\min\{A_{j+1},A_{j+2},\cdots,A_i\}\)
\(dp\) 可以用线段树优化,第 \(j\) 个节点记录 $dp(j)\max/\min{A_{j+1},A_{j+2},\cdots,A_i} $ .
但是最大值/最小值可能会变,套路地用 \(\mathrm{stack}\) 维护,然后乘上之前最大值/最小值的逆元之后乘上当前最大值/最小值.
因为每个元素只会进栈出栈依次,分析得到总的修改次数是 \(O(n)\) 级别的 .
时间复杂度 : \(O(n\log n)\)
空间复杂度 : \(O(n)\)
code
#include<bits/stdc++.h>
using namespace std;
char in[100005];
int iiter=0,llen=0;
inline char get(){
if(iiter==llen)llen=fread(in,1,100000,stdin),iiter=0;
if(llen==0)return EOF;
return in[iiter++];
}
inline int rd(){
char ch=get();while(ch<'0'||ch>'9')ch=get();
int res=0;while(ch>='0'&&ch<='9')res=(res<<3)+(res<<1)+ch-'0',ch=get();
return res;
}
inline void pr(int res){
if(res==0){putchar('0');return;}
static int out[10];int len=0;
while(res)out[len++]=res%10,res/=10;
for(int i=len-1;i>=0;i--)putchar(out[i]+'0');
}
const int N=3e5+10;
const int mod=998244353;
class segtree{
public:
int ts[N<<2],tag[N<<2];
void init(){
memset(ts,0,sizeof(ts));
memset(tag,1,sizeof(tag));
}
inline void pd(int x){
if(tag[x]==1)return;
ts[x<<1]=1ll*ts[x<<1]*tag[x]%mod;
ts[x<<1|1]=1ll*ts[x<<1|1]*tag[x]%mod;
tag[x<<1]=(tag[x<<1]+tag[x])%mod;
tag[x<<1|1]=(tag[x<<1|1]+tag[x])%mod;
tag[x]=1;
}
void upd(int x,int l,int r,int pos,int val){
if(l==r){
ts[x]=val;
return;
}
pd(x);
int mid=(l+r)>>1;
if(pos<=mid)upd(x<<1,l,mid,pos,val);
else upd(x<<1|1,mid+1,r,pos,val);
ts[x]=(ts[x<<1]+ts[x<<1|1])%mod;
}
void upd(int x,int l,int r,int cl,int cr,int val){
if(l==cl&&r==cr){
if(l!=r)pd(x);
tag[x]=(tag[x]+val)%mod;
ts[x]=1ll*ts[x]*val%mod;
return;
}
pd(x);
int mid=(l+r)>>1;
if(cr<=mid)upd(x<<1,l,mid,cl,cr,val);
else if(mid+1<=cl)upd(x<<1|1,mid+1,r,cl,cr,val);
else upd(x<<1,l,mid,cl,mid,val),upd(x<<1|1,mid+1,r,mid+1,cr,val);
ts[x]=(ts[x<<1]+ts[x<<1|1])%mod;
}
}T1,T2;
inline int ksm(int x,int k){
if(k==0)return 1;
int res=ksm(x,k>>1);
res=1ll*res*res%mod;
if(k&1)res=1ll*res*x%mod;
return res;
}
int n;
int a[N];
int dp[N];
stack<pair<int,int> >s1,s2;//max&min
int main(){
n=rd();
for(int i=0;i<n;i++)a[i]=rd();
T1.init();T2.init();
cerr<<n<<endl;
dp[0]=1;
T1.upd(1,0,n-1,0,dp[0]);
T2.upd(1,0,n-1,0,dp[0]);
for(int i=1;i<=n;i++){
while(!s1.empty()&&s1.top().first<=a[i-1]){
pair<int,int>p=s1.top();s1.pop();
T1.upd(1,0,n-1,(s1.empty()?0:s1.top().second+1),p.second,ksm(p.first,mod-2));
}
T1.upd(1,0,n-1,(s1.empty()?0:s1.top().second+1),i-1,a[i-1]);
s1.push(make_pair(a[i-1],i-1));
while(!s2.empty()&&s2.top().first>=a[i-1]){
pair<int,int>p=s2.top();s2.pop();
T2.upd(1,0,n-1,(s2.empty()?0:s2.top().second+1),p.second,ksm(p.first,mod-2));
}
T2.upd(1,0,n-1,(s2.empty()?0:s2.top().second+1),i-1,a[i-1]);
s2.push(make_pair(a[i-1],i-1));
dp[i]=(T1.ts[1]-T2.ts[1]+mod)%mod;
if(i<n)T1.upd(1,0,n-1,i,dp[i]);
if(i<n)T2.upd(1,0,n-1,i,dp[i]);
}
pr(dp[n]);putchar('\n');
return 0;
}
/*inline? ll or int? size? min max?*/
Ex - Enumerate Pairs
鸽鸽鸽 🕊

浙公网安备 33010602011771号