A. Planets

题意:给你一个序列 aaa,你可以分别进行如下操作任意次:

  • 花费 \(1\) 的代价删除 \(a_i\)
  • 花费 \(c\) 的代价删除 \(\forall a_i=x\)\(x\) 自定。

求删除整个序列的最小代价。多测。

解法:没啥好说的,暴力

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<vector>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=2200,mod=998244353;
int a[WR],cnt[WR];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    int T=read();
    while(T--){
        int n=read(),c=read();
        int ans=0;
        for(int i=1;i<=n;i++) a[i]=read(),cnt[a[i]]++;
        for(int i=1;i<WR;i++){
            if(cnt[i]>=c) ans+=c,cnt[i]=0;
            else ans+=cnt[i],cnt[i]=0;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

B. Meeting on the Line

题意:给定一个长为 \(n\) 的序列 \(a\)\(t\),请你求出一个 \(x_0\),使得 \(\max\limits_{i=1}^{n}\{t_i+|a_i-x_0|\}\) 最小化,输出 \(x_0\)

解法:注意到这个 \(t\) 完全可以合并进距离,假如说 \(x_0\)\(a_i\) 右侧,则可以将 \(a_i\) 再左移 \(t\)
在左边同理
那我们就人工给 \(a_i\) 加/减 \(t_i\) ,然后求一个坐标最大一个坐标最小加起来除以 \(2\) 即可

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<vector>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=2200000,mod=998244353,INF=9e18;
int a[WR],c[WR];
int read(){
    int s=0,w=1;    
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    int T=read();
    while(T--){
        int n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++) c[i]=read();
        int maxx=0,minn=INF;
        for(int i=1;i<=n;i++){
            maxx=max(maxx,a[i]+c[i]);
            minn=min(minn,a[i]-c[i]);
        }
        printf("%.8lf\n",(double)(maxx+minn)/2.0);
    }
    return 0;
}

C. Minimum Notation

题意:给定一个仅包含 \(0\)\(9\) 这几个数字的字符串,你可以执行以下操作任意次:
选择字符串中的一个数字 \(d\),将 \(d\) 删除后,向字符串任意位置插入一个数字 \(\min(d+1,9)\)
求能够得到的字典序最小的字符串。

解法:又是意识流写出来的
不难发现我们肯定要保留目前序列里最小的数字,并且把它们尽量往前放
如果有其它的数在最小数的前面我们统一把它们扔到后面去,这样肯定更优
因此记录一个最小值,再记录一个最小值的后缀和,枚举每一位判断
具体来说,维护一个 \(cnt\) 数组,如果当前值 \(x\) 是最小值,\(cnt[x]+1\)
否则 \(cnt[\min(x+1,9)]+1\)
当最小值后缀和为 \(0\) 的时候更新最小值即可
(代码里好像还有没啥用的前缀和?)

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<vector>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=220000,mod=998244353,INF=9e18;
int a[WR],pre[WR][10],suf[WR][10];
int cnt[WR];
char str[WR];
int read(){
    int s=0,w=1;    
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    int T=read();
    while(T--){
        scanf("%s",str+1);
        int n=strlen(str+1);
        for(int i=0;i<=9;i++) cnt[i]=0;
        for(int i=1;i<=n;i++) a[i]=str[i]-'0';
        for(int i=0;i<=n+1;i++){
            for(int j=0;j<=9;j++){
                pre[i][j]=suf[i][j]=0;
            }
        }
        for(int i=1;i<=n;i++){
            pre[i][a[i]]++;
            for(int j=0;j<=9;j++){
                pre[i][j]+=pre[i-1][j];
            }
        }
        for(int i=n;i>=1;i--){
            suf[i][a[i]]++;
            for(int j=0;j<=9;j++){
                suf[i][j]+=suf[i+1][j];
            }
        }
        // for(int i=1;i<=n;i++){
        //     for(int j=0;j<=9;j++){
        //         printf("i=%lld num=%lld pre=%lld suf=%lld\n",i,j,pre[i][j],suf[i][j]);
        //     }
        // }
        int pos=0;
        for(int i=1;i<=n;i++){
            while(!suf[i][pos]) pos++;
            if(a[i]!=pos) cnt[min(a[i]+1,9ll)]++;
            else cnt[a[i]]++;
        }
        for(int i=0;i<=9;i++){
            for(int j=1;j<=cnt[i];j++) printf("%lld",i);
        }
        printf("\n");
    }
    return 0;
}

D. Prefixes and Suffixes

题意:有两个字符串 \(s~,~t\) ,每次可以交换长度为 \(k\)\(s\) 的前缀和 \(t\) 的后缀,可以操作任意次,判断操作是否可能使得 \(s=t\)

解法:手玩样例会发现无论如何变换, \(s_i\)\(t_{n-i+1}\) 的相对位置是不变的
然后又发现对于这样的一对字符,可以将其移动到任意位置
小证一下:假设要从 \(s_p\) 移动到 \(s_q\) 那么可以先交换 \(p\) 再交换 \(q\)
考虑用这个搞搞事情
注意到一对字符若不同则必定出现偶数次,如果相同则只能在 \(n\) 为奇数时有单独一个出现奇数次
维护一个 \(cnt\) 数组记录每对数的出现次数即可

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<vector>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=220000,mod=998244353,INF=9e18;
char a[WR],b[WR];
int cnt[30][30];
int read(){
    int s=0,w=1;    
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    int T=read();
    while(T--){
        memset(cnt,0,sizeof(cnt));
        int n=read();
        scanf("%s%s",a+1,b+1);
        for(int i=1;i<=n;i++){
            int vala=a[i]-'a'+1,valb=b[n-i+1]-'a'+1;
            if(vala>valb) swap(vala,valb);
            cnt[vala][valb]++;
        }
        int tot=0,flag=true;
        for(int i=1;i<=26;i++){
            tot+=(cnt[i][i]%2);
            for(int j=i+1;j<=26;j++){
                // printf("%lld %lld %lld\n",i,j,cnt[i][j]);
                if(cnt[i][j]&1){
                    flag=false;break;
                }
            }
            if(!flag) break;
        }
        if(!flag||tot>(n&1)) printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}

E. Maximums and Minimums

题意:给定一个长度为 \(n\) 数组 \(a\),求有多少个区间 \([l, r]\),满足区间最大值是最小值的倍数

image

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<iostream>
#include<vector>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=1001000,mod=998244353,INF=9e18;
vector<int>d[WR];
int cnt[WR];
int minn[WR>>1][19],lg[WR];
stack<int>stk;
int read(){
    int vec=0,w=1;    
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        vec=(vec<<3)+(vec<<1)+ch-'0';
        ch=getchar();
    }
    return vec*w;
}
void sieve(int n=WR-1){
    for(int i=1;i<=n;i++){
        cnt[i]=-1;
        for(int j=i*2;j<=n;j+=i){
            d[j].emplace_back(i);
        }
    }
}
void STable(int n){
    lg[0]=-1;
    for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
    for(int j=1;j<=lg[n];j++){
        for(int i=1;i<=n-(1<<j)+1;i++){
            minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
        }
    }
}
int query(int l,int r){
    int tmp=lg[r-l+1];
    return min(minn[l][tmp],minn[r-(1<<tmp)+1][tmp]);
}
int n;
int a[WR],pre[WR],suf[WR],st[WR],ed[WR];
vector<int>vec[WR];
void solve(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=minn[i][0]=read(),vec[a[i]].emplace_back(i);
    STable(n);
    while(!stk.empty()) stk.pop();
    for(int i=1;i<=n;i++){
        while(!stk.empty()&&a[stk.top()]>=a[i]) stk.pop();
        if(!stk.empty()) pre[i]=stk.top();
        else pre[i]=0;
        stk.push(i);
    }
    while(!stk.empty()) stk.pop();
    for(int i=n;i>=1;i--){
        while(!stk.empty()&&a[stk.top()]>=a[i]) stk.pop();
        if(!stk.empty()) suf[i]=stk.top();
        else suf[i]=n+1;
        stk.push(i);
    }
    while(!stk.empty()) stk.pop();
    for(int i=1;i<=n;i++){
        while(!stk.empty()&&a[stk.top()]<a[i]) stk.pop();
        if(!stk.empty()) st[i]=stk.top();
        else st[i]=0;
        stk.push(i);
    }
    while(!stk.empty()) stk.pop();
    for(int i=n;i>=1;i--){
        while(!stk.empty()&&a[stk.top()]<=a[i]) stk.pop();
        if(!stk.empty()) ed[i]=stk.top();
        else ed[i]=n+1;
        stk.push(i);
    }
    // for(int i=1;i<=n;i++) printf("%lld %lld\n",pre[i],suf[i]);
    int ans=0;
    for(int i=1;i<=n;i++){
        int l=st[i]+1,r=ed[i]-1;
        ans+=(min(r+1,suf[i])-i)*(i-max(l-1,pre[i]));
        // printf("ans:%lld\n",ans);
        for(int j=0;j<d[a[i]].size();j++){
            int x=d[a[i]][j];
            if(cnt[x]>=0&&cnt[x]<(int)vec[x].size()-1&&l<=vec[x][cnt[x]]&&vec[x][cnt[x]+1]<=r){
                int pl=vec[x][cnt[x]],pr=vec[x][cnt[x]+1];
                if(query(pl+1,i)>x&&query(i,pr-1)>x){
                    ans+=(pl-max(l-1,pre[pl]))*(min(r+1,suf[pr])-i);
                    ans+=(i-max(l-1,pre[pl]))*(min(r+1,suf[pr])-pr);
                    ans-=(pl-max(l-1,pre[pl]))*(min(r+1,suf[pr])-pr);
                }else if(query(pl+1,i)>x){
                    ans+=(pl-max(l-1,pre[pl]))*(min(r+1,suf[pl])-i);
                }else if(query(i,pr-1)>x){
                    ans+=(min(r+1,suf[pr])-pr)*(i-max(l-1,pre[pr]));
                }
            }else if(cnt[x]>=0&&l<=vec[x][cnt[x]]){
                int p=vec[x][cnt[x]];
                if(query(p+1,i)>x){
                    ans+=(min(r+1,suf[p])-i)*(p-max(l-1,pre[p]));
                }
            }else if(cnt[x]<(int)vec[x].size()-1&&vec[x][cnt[x]+1]<=r){
                int p=vec[x][cnt[x]+1];
                if(query(i,p-1)>x){
                    ans+=(min(r+1,suf[p])-p)*(i-max(l-1,pre[p]));
                }
            }
        }
        // printf("ans:%lld\n",ans);
        cnt[a[i]]++;
    }
    printf("%lld\n",ans);
    for(int i=1;i<=n;i++) cnt[a[i]]=-1,vec[a[i]].clear();
}
signed main(){
    sieve();
    int T=read();
    while(T--) solve();
    return 0;
}

原文地址:http://www.cnblogs.com/WintersRain/p/16882137.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性