CF1870 div1+div2做题记录

发布时间 2023-09-19 22:09:54作者: luo_shen

A

题面

挺蠢的,无解条件为 \(n<k\)\(x<k-1\),即 \(\mathop{\mathrm{mex}}\not=k\)。先选 \(0\sim k-1\),再选能选的最大值,当 \(x=k\),选 \(x-1\),否则选 \(x\)

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
void solve(){
    int n,k,x;
    read(n),read(k),read(x);
    if(k-1>x||k>n){
        puts("-1");
        return;
    }
    int sum=(k-1)*k/2;
    if(x==k){
        sum+=(n-k)*(k-1);
    }
    else{
        sum+=(n-k)*x;
    }
    write_endl(sum);
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t;
    read(t);
    while(t--){
        solve();
    }
    return 0;
}

B

题面

分位讨论,如果一个或上一个 \(b_i\),对于它二进制上的每一个 \(1\) 的位置有什么影响。若 \(n\) 为偶数,显然或上之后这一位一定为 \(0\),否则一定为 \(1\)

对于 \(n\) 为奇数时,所有数在或上一个 \(b_i\) 后异或和一定不会变小,对于 \(n\) 为偶数时,或上一个 \(b_i\) 后异或和一定不会变大,所以要么全或,要么全不或。直接计算两个极端的值,然后按 \(n\) 的奇偶性以不同的顺序输出两个数。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=2e5+10;
int n,m,a[N],b[N];
void solve(){
    int xsum=0,osum=0;
    read(n),read(m);
    for(int i=1;i<=n;i++){
        read(a[i]);
        xsum^=a[i];
    }
    for(int j=1;j<=m;j++){
        read(b[j]);
        osum|=b[j];
    }
    if(n%2==1){
        write_space(xsum);
        int s=0;
        for(int i=1;i<=n;i++){
            s^=(a[i]|osum);
        }
        write_endl(s);
    }
    else{
        int s=0;
        for(int i=1;i<=n;i++){
            s^=(a[i]|osum);
        }
        write_space(s);
        write_endl(xsum);
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t;
    read(t);
    while(t--){
        solve();
    }
    return 0;
}

C

题面

如果存在一个 \(j\) 满足 \(j\le i,a_j\ge a_i\)\(a_i\) 答案的左侧和上方的界限要划到对应行和对应列,同理右侧和下方也一样。按权值从大到小找答案即可。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=1e5+10;
vector<int>sum[N];
int n,a[N],k,ans[N];
void solve(){
    read(n),read(k);
    for(int i=1;i<=k;i++){
        sum[i].clear();
    }
    for(int i=1;i<=n;i++){
        read(a[i]);
        sum[a[i]].pb(i);
    }
    int mn=n+1,mx=0;
    for(int i=k;i>=1;i--){
        if(sum[i].size()==0){
            ans[i]=0;
            continue;
        }
        mn=min(mn,sum[i].front());
        mx=max(mx,sum[i].back());
        ans[i]=(mx-mn+1)*2;
    }
    for(int i=1;i<=k;i++){
        write_space(ans[i]);
    }
    putchar('\n');
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t;
    read(t);
    while(t--){
        solve();
    }
    return 0;
}

D

题面

因为要字典序最大,我们最基本要让 \(1\) 的值最大,找到代价最小的位置,如果有多个代价最小的位置,选最后一个位置,令该位置为 \(p\),这样可以使得答案其它位置的答案也更大。如果此时还有多余的代价,因为 \(p\) 以前的位置都已经尽量大了,所以我们只能考虑将一些 \(p\) 处的贡献往后移动到代价更大的位置产生贡献,将所有的代价减去 \(p\) 后,能够发现这还是上述操作,重复进行操作直到 \(p=n\) 为止。看得出来,这个操作序列 \(p\) 的代价的序列就是原序列的单调栈中的权值,维护一个单调上升的单调栈就行。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=2e5+10;
int n,c[N],k,cnt[N],stk[N],top;
void solve(){
    read(n);
    for(int i=1;i<=n;i++){
        read(c[i]);
        cnt[i]=0;
    }
    read(k);
    top=0;
    for(int i=1;i<=n;i++){
        while(top&&c[stk[top]]>=c[i]){
            top--;
        }
        stk[++top]=i;
    }
    cnt[0]=inf;
    for(int i=1;i<=top;i++){
        cnt[stk[i]]=min(cnt[stk[i-1]],k/(c[stk[i]]-c[stk[i-1]]));
        cnt[stk[i-1]]-=cnt[stk[i]];
        k-=cnt[stk[i]]*(c[stk[i]]-c[stk[i-1]]);
    }
    for(int i=n-1;i;i--){
        cnt[i]+=cnt[i+1];
    }
    for(int i=1;i<=n;i++){
        write_space(cnt[i]);
    }
    putchar('\n');
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t;
    read(t);
    while(t--){
        solve();
    }
    return 0;
}

E

题面

\(f_{i,j}\) 表示前 \(i\) 个位置中能得否划分处若干个区间使得 \(\mathop{\mathrm{mex}}\) 异或得到 \(j\)

可以用 \(O(n^2)\) 的复杂度处理出区间 \([i,j]\)\(\mathop{\mathrm{mex}}\)。为了保证复杂度,需要去重,只存下 \(\mathop{\mathrm{mex}}_{[i,j]}/not=\mathop{\mathrm{mex}}_{[i,j-1]}\)\(\mathop{\mathrm{mex}}_{[i,j]}/not=\mathop{\mathrm{mex}}_{[i+1,j]}\)\(\mathop{\mathrm{mex}}\)。这样的 \(\mathop{\mathrm{mex}}_{[i,j]}\) 的数量是 \(O(n)\) 级别的。\(j\) 的可以转移来的位置只有存下来的 \(\mathop{\mathrm{mex}}_{[i,j]}\) 所对应的 \(i-1\)。复杂度就变成了 \(O(nV)\) 级别了。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=5e3+10,M=8192+10;
int n,a[N],mex[N][N],cnt[M];
bool f[N][M];
vector<pii>num[N];
void solve(){
    read(n);
    for(int i=1;i<=n;i++){
        read(a[i]);
    }
    int mx=*max_element(a+1,a+n+1);
    for(int i=0;;i++){
        if((1<<i)>mx+1){
            mx=(1<<i)-1;
            break;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<=mx;j++){
            cnt[j]=0;
        }
        int pos=0;
        for(int j=i;j<=n;j++){
            cnt[a[j]]++;
            while(cnt[pos]){
                pos++;
            }
            mex[i][j]=pos;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            if(mex[i][j]!=mex[i][j-1]&&mex[i][j]!=mex[i+1][j]){
                num[j].pb(mp(i,mex[i][j]));
            }
        }
    }
    f[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=mx;j++){
            f[i][j]=f[i-1][j];
            if(f[i-1][j]){
                continue;
            }
            for(auto x:num[i]){
                int pre=x.first,nxt=x.second;
                f[i][j]|=f[pre-1][j^nxt];
            }
        }
    }
    for(int i=mx;i>=0;i--){
        if(f[n][i]){
            write_endl(i);
            break;
        }
    }
    for(int i=0;i<=mx;i++){
        cnt[i]=0;
    }
    for(int i=0;i<=n;i++){
        for(int j=0;j<=mx;j++){
            f[i][j]=0;
        }
        for(int j=0;j<=n;j++){
            mex[i][j]=0;
        }
        num[i].clear();
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t;
    read(t);
    while(t--){
        solve();
    }
    return 0;
}

F

题面

考虑将 \(1\sim n\) 全部化为 \(k\) 进制,将其放到trie上,可以发现两种数列b分别为bfs序和dfs序得到的数列,答案要找的数就是bfs序减dfs序结果为 \(0\) 的点。考虑将trie拆成若干行,对于每行计算答案,可以二分找到贡献答案的范围。总复杂度 \(O(t\log n^3)\)

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int __int128
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
int n,k,tot,L[100],R[100],ans;
void init(){
    ans=0,tot=0;
    for(int l=1,r;l<=n;l=r+1){
        r=min(l*k-1,n);
        L[++tot]=l,R[tot]=r;
    }
}
int get(int x,int cur){
    int ans=-x+1,mul=1;
    for(int i=cur-1;i;i--){
        mul=mul*k;
        ans+=x/mul-L[i]+1;
    }
    mul=1;
    for(int i=cur;i<=tot;i++){
        ans+=min(x*mul-1,n)-L[i]+1;
        mul*=k;
    }
    return ans;
}
void solve(){
    read(n),read(k);
    if(n<k){
        write_endl(n);
        return;
    }
    init();
    for(int i=1;i<=tot;i++){
        int ansl=R[i]+1,ansr=R[i]+1;
        int l=L[i],r=R[i];
        while(l<=r){
            int mid=(l+r)>>1;
            if(get(mid,i)>=0){
                ansl=mid;
                r=mid-1;
            }
            else{
                l=mid+1;
            }
        }
        l=L[i],r=R[i];
        while(l<=r){
            int mid=(l+r)>>1;
            if(get(mid,i)>0){
                ansr=mid;
                r=mid-1;
            }
            else{
                l=mid+1;
            }
        }
        ans+=ansr-ansl;
    }
    write_endl(ans);
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t;
    read(t);
    while(t--){
        solve();
    }
    return 0;
}