Codeforces Round #567 (Div. 2)

A

签到(code不贴了)

PS:以后cf div2A(有时还有B)和atcoder <=200分(有时<=300)的题目不再贴code,不过可能也没几次比赛记录了。

B

高精度,枚举位数最短的可能,然后计算两个即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
struct node{int n,a[N];}ans,a,b;
int n,mn;
vector<int>G;
char s[N];
bool check(node a,node b)
{
    if(a.n!=b.n)return a.n<b.n;
    for(int i=a.n;i;i--)
    if(a.a[i]<b.a[i])return 1;
    else if(a.a[i]>b.a[i])return 0;
    return 0;
}
node operator+(node a,node b)
{
    if(a.n<b.n)swap(a,b);
    for(int i=1;i<=a.n;i++)
    {
        a.a[i]+=b.a[i];
        if(a.a[i]>=10)a.a[i]-=10,a.a[i+1]++;
    }
    if(a.a[a.n+1])a.n++;
    return a;
}
void split(int p)
{
    a.n=p;
    for(int i=1;i<=p;i++)a.a[p-i+1]=s[i]-'0';
    for(int i=p+1;i<N;i++)a.a[i]=0;
    b.n=n-p;
    for(int i=p+1;i<=n;i++)b.a[n-i+1]=s[i]-'0';
    for(int i=n-p+1;i<N;i++)b.a[i]=0;
    a=a+b;
    if(check(a,ans))ans=a;
}
int main()
{
    scanf("%d",&n);
    if(n==2){cin>>n,cout<<n/10+n%10;return 0;}
    scanf("%s",s+1);
    mn=n+2,ans.n=n+2;
    for(int i=1;i<n;i++)
    if(s[i+1]!='0')
    {
        int len=max(i,n-i);
        if(len<mn)mn=len,G.clear(),G.push_back(i);
        else if(len==mn)G.push_back(i);
    }
    for(int i=0;i<G.size();i++)split(G[i]);
    for(int i=ans.n;i;i--)printf("%d",ans.a[i]);
}
View Code

C

太难了吧,简直被搞自闭了,WA了3发,主要是细节过多。实际上就是一个朴素O(nm)DP,f[i][j]表示以(i,j)为右下角的旗子个数,然后u[i][j]表示同色往上走的距离,注意第一段的距离是>=后面两端,而不是=,第二发这里WA了。第一发是只判了长度没判颜色。第三发是把长度都默认成1了。严重影响做题心态。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1007;
int n,m,u[N][N];
ll ans,f[N][N];
char a[N][N];
int check(int i,int j)
{
    int len=u[i][j];
    i-=u[i][j];
    if(u[i][j]!=len)return 0;
    i-=u[i][j];
    return len*(u[i][j]>=len);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    if(i==1||a[i][j]!=a[i-1][j])u[i][j]=1;
    else u[i][j]=u[i-1][j]+1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        int v=check(i,j);
        if(!v)continue;
        f[i][j]=1;
        if(j>1&&v==check(i,j-1)&&a[i][j]==a[i][j-1]&&a[i-v][j]==a[i-v][j-1]&&a[i-2*v][j]==a[i-2*v][j-1])f[i][j]+=f[i][j-1];
        ans+=f[i][j];
    }
    cout<<ans;
}
View Code

D

离线做法显然,把询问从小到大排序,然后扫的时候记录扫到了第几层(如果全部填满特判一下,很简单qwq),对于其余的次数,可以做一棵权值线段树。

其实这题真的可以加强,加强法是把n设为1e5,然后强制在线(讲真这是我第一想法,不过比较难写)。

#include<bits/stdc++.h>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
const int N=5e5+7;
struct node{ll x;int id;}q[N];
int n,m,Q,mx,ans[N],sum[N<<2],sz[N];
ll s[N];
vector<int>G[N];
bool cmp(node a,node b){return a.x<b.x;}
void update(int k,int l,int r,int rt)
{
    if(l==r){sum[rt]=1;return;}
    int mid=l+r>>1;
    if(k<=mid)update(k,lson);else update(k,rson);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int query(int v,int l,int r,int rt)
{
    if(l==r)return l;
    int mid=l+r>>1;
    if(v>sum[rt<<1])return query(v-sum[rt<<1],rson);
    return query(v,lson);
}
int main()
{
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1,x;i<=n;i++)scanf("%d",&x),s[x]++,mx=max(mx,(int)s[x]);
    for(int i=1;i<=m;i++)G[s[i]].push_back(i);
    for(int i=1;i<=Q;i++)scanf("%I64d",&q[i].x),q[i].id=i,q[i].x-=n;
    sort(q+1,q+Q+1,cmp);
    for(int i=0;i<=mx;i++)sort(G[i].begin(),G[i].end()),s[i]=0;
    sz[0]=G[0].size();for(int i=1;i<=mx;i++)sz[i]=sz[i-1]+G[i].size();
    s[0]=sz[0];for(int i=1;i<=mx;i++)s[i]=s[i-1]+sz[i];
    for(int i=0;i<G[0].size();i++)update(G[0][i],1,m,1);
    for(int i=1,p=0;i<=Q;i++)
    if(s[mx]<q[i].x)ans[q[i].id]=(q[i].x-s[mx]-1)%m+1;
    else{
        while(p<=mx&&s[p]<q[i].x)
        {
            p++;
            for(int i=0;i<G[p].size();i++)update(G[p][i],1,m,1);
        }
        if(p)q[i].x-=s[p-1];
        ans[q[i].id]=query(q[i].x,1,m,1);
    }
    for(int i=1;i<=Q;i++)printf("%d\n",ans[i]);
}
View Code

E

咕。

result:rank37 rating+=157,毕竟这是我第4个号……

猜你喜欢

转载自www.cnblogs.com/hfctf0210/p/11037203.html