Codeforces 1181

1181 B

题意

一个高精整数,要把它从中间割开分成两部分,每一部分不能为空也不能有前导零,问如何才能使得两部分的和最小。

Examples

input
7
1234567
output
1801
input
3
101
output
11

打高精好点烦的
就均分成两半,再判一判前导零就好了。

1181 C

题意

旗帜的定义:
这些是旗帜:
4a648125bec514dff30deb334abd5172dd9e2a83.png
079ca96e3ff880d51583777aedfeec62d3e9aa2f.png
8f9f1d38918466ad9fe677c772e10f892f880f5d.png

这些不是旗帜:
5a3b9932288eff8f687d058473f557e623d449cf.png
0a0bdca2c76ac417e9dfdd017eb258fd99c7a482.png
e380173ead80fc0b40362cb1ea6b1df7e2e5024a.png
1b312839eea4c67991fc3bd3dfee4aa520851f02.png
ed12722f8784d67267f329c660eb658679f1286d.png
3534f94d3af27b44f06d85ce9d0411a7c353077f.png

现在给你一个英文字母矩阵,问有多少个子矩形是旗帜。 \((n,m\le 1000)\)

Examples

input
4 3
aaa
bbb
ccb
ddd
output
6
input
6 1
a
a
b
b
c
c
output
1
input
4 3
aca
ccc
bbb
aaa
output
8

弄一个双端队列模拟即可。
细节较多。

Code

#include<bits/stdc++.h>
using namespace std;
typedef pair<char,int> P;
const int maxn=1003,INF=1050000000;
char s[maxn];
int n,m;
long long ans;
deque<P> a[maxn];
bool valid(const deque<P> &q){
    return q.size()==3&&q[0].second>=q[1].second&&q[1].second==q[2].second;
}
bool equal(const deque<P> &q1,const deque<P> &q2){
    if(q2.size()!=3)return 0;
    for(int i=0;i<=2;i++)if(q1[i].first!=q2[i].first)return 0;
    return q1[1].second==q2[1].second&&q1[2].second==q2[2].second;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++){
            if(a[j].size()>=1&&a[j].back().first==s[j])a[j].back().second++;
            else a[j].push_back(P(s[j],1));
            while(a[j].size()>=2&&a[j].back().second>a[j][a[j].size()-2].second)a[j].pop_front();
            if(a[j].size()>=4)a[j].pop_front();
        }
        for(int l=1,r=1;r<=m;l=r){
            for(;l<=m&&!valid(a[l]);l++);
            for(r=l;r<=m&&valid(a[r])&&equal(a[l],a[r]);r++);
            ans+=(long long)(r-l)*(r-l+1)/2;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

1181 D

题意

\(m\) 个城市,每年举办比赛。在最先的 \(n\) 年中比赛的举办地是已知的,后来制定了规则,每年以每个城市之前举办次数为第一关键字,以每个城市的编号为第二关键字,选择最小的城市举办比赛。现在有 \(q\) 个询问,每次询问第 \(x_i\) 年由哪个城市举办。 \((1\le n,m,q\le 5*10^5,x_i\le 10^{18})\)

Examples

input
6 4 10
3 1 1 1 2 2
7
8
9
10
11
12
13
14
15
16
output
4
3
4
2
3
4
1
2
3
4
input
4 5 4
4 4 5 1
15
9
13
6
output
5
3
3
3

模拟发现,经过 \(O(n^2)\) 年,举办城市必定会变成 \(1,2,\dots ,m\) 的顺序。
因此,在临界值之后的询问很容易得出结果。
在临界值之前的询问呢?
考虑将每个城市按上述两个关键字排序,然后对于每个第一关键字相等的区间设它们为 \([l_i...r_i](r_i+1=l_{i+1},l_1=1)\) 我们发现举办城市的顺序就是:

  • \(1\)\(r_1\) 轮流,进行 \(cnt[l_2]-cnt[1]\) 遍;
  • \(\dots\)
  • \(1\)\(r_{i+1}\) 轮流,进行 \(cnt[l_{i+2}]-cnt[l_{i+1}]\) 遍;
  • \(\dots\)
  • \(1\)\(r_{k-1}\) 轮流,进行 \(cnt[l_k]-cnt[l_{k-1}]\) 遍;
  • \(1\)\(m\) 轮流,进行 \(∞\) 遍(这是临界值之后)。

每次相当于一轮轮完之后把 \([1,r_i]\)\([l_{i+1},r_{i+1}]\) 合并。
\(n^2\) 归并显然是不行的,因此我们用一种数据结构来实现每个城市的名次查询。

Code

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
typedef pair<long long,int> QQ;
const int maxn=500003,INF=1050000000;
P a[maxn];
QQ q[maxn];
int n,m,Q,ans[maxn],t[maxn<<2];
int mod(long long x,int y){return x%y==0?y:x%y;}
void change(int p,int l,int r,int pos){
    if(l==r){
        t[p]++;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)change(p<<1,l,mid,pos);
    else change(p<<1|1,mid+1,r,pos);
    t[p]=t[p<<1]+t[p<<1|1];
}
int kth(int p,int l,int r,int rnk){
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(rnk<=t[p<<1])return kth(p<<1,l,mid,rnk);
    else return kth(p<<1|1,mid+1,r,rnk-t[p<<1]);
}
int main(){
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        a[x].first++;
    }
    for(int i=1;i<=m;i++)a[i].second=i;
    sort(a+1,a+m+1);
    for(int i=1;i<=Q;i++)scanf("%lld",&q[i].first),q[i].second=i;
    sort(q+1,q+Q+1);
    int l,r,pos;
    long long now=n,nxt;
    for(l=1,r=1,pos=1;;l=r){
        for(;r<=m&&a[r].first==a[l].first;r++)change(1,1,m,a[r].second);
        if(r>m)break;
        nxt=now+(long long)(a[r].first-a[l].first)*(r-1);
        for(;pos<=Q&&q[pos].first<=nxt;pos++){
            ans[q[pos].second]=kth(1,1,m,mod(q[pos].first-now,r-1));
        }
        now=nxt;
    }
    for(;pos<=Q;pos++){
        ans[q[pos].second]=mod(q[pos].first-now,m);
    }
    for(int i=1;i<=Q;i++)printf("%d\n",ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/BlogOfchc1234567890/p/11051532.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值