AtCoder Beginner Contest 363

AtCoder Beginner Contest 363

A - Piling Up

每100分显示一个^。现在已知分数,问想要多显示一个^需要再得多少分。

模拟题,显示\(i\)^的最小分数是\(100\times i\),而当前的^\([\frac{R}{100}]\)\(R\)是当前的分数。

所以答案就是\(([\frac{R}{100}]+1)\times 100-R\)

#include<iostream>
#include<cstdio>
using namespace std;
int R;
int main()
{
    cin>>R;
    int display=R/100;
    cout<<(display+1)*100-R<<endl;
    return 0;
}

B - Japanese Cursed Doll

\(n\)个数,第\(i\)个是\(L_i\),每个数在每个时刻都会增长\(1\)。问在哪个时刻第一次有\(P\)个数会大于等于\(T\)。如果初始时就满足条件,则输出\(0\)

\(L\)从小往大排序,那么只需要第\(n-P+1\)大的数满足条件即可,假设这个数是\(a\)。因此,只需要计算\(T-a\)即可。注意,如果这个数是负数,意味着初始时就满足条件,此时要输出\(0\)

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX=105;
int n,T,P;
int L[MAX];
int main()
{
    cin>>n>>T>>P;
    for(int i=1;i<=n;++i)cin>>L[i];
    sort(&L[1],&L[n+1]);
    int l=L[n-P+1];
    int ans=max(0,T-l);
    cout<<ans<<endl;
    return 0;
}

C - Avoid K Palindrome 2

有一个长度为\(n\)的字符串\(S\)。问有多少个字符串满足:1、通过\(S\)重排列得到;2、没有一个长度为\(K\)的回文子串。

注意数据范围,完全可以依次枚举每一个排列,可以使用next_permutation函数。接着暴力判断是否拥有回文子串即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k,ans;
char c[15];
int main()
{
    scanf("%d%d",&n,&k);
    scanf("%s",c+1);
    sort(&c[1],&c[n+1]);
    do    
    {
        bool flag=true;
        for(int i=1;i+k-1<=n;++i)
        {
            bool f=true;
            for(int j=0;j<k;++j)
                if(c[i+j]!=c[i+k-1-j])
                    f=false;
            if(f)flag=false;
        }
        if(flag)++ans;
    }while(next_permutation(&c[1],&c[n+1]));
    printf("%d\n",ans);
    return 0;
}

D - Palindromic Number

求第\(k\)大的回文数。

回文数只需要考虑前一半就可以构造。
枚举长度,首先计算出答案回文数的长度。通过枚举和减法可以计算出是当前长度下第\(k\)大的回文数。
而前一半就是顺序的,第\(k\)大就是当前长度的数的第\(k\)大,这个很好求。
接下来只需要构成回文,直接输出即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long N;
long long fpow(long long a,long long b)
{
    long long ret=1;
    while(b)
    {
        if(b&1)ret*=a;
        a*=a;
        b>>=1;
    }
    return ret;
}
int a[1000];
int main()
{
    cin>>N;
    N-=1;
    if(N<10)
    {
        printf("%lld\n",N);
        return 0;
    }
    int l=1;
    while(true)
    {
        int t=(l+1)>>1;
        long long m=9ll*fpow(10,t-1);
        if(N>m)N-=m;
        else break;
        ++l;
    }
    int t=(l+1)>>1;
    int len=0;
    N-=1;
    while(N)a[++len]=N%10,N/=10;
    a[t]+=1;
    for(int i=t;i;--i)printf("%d",a[i]);
    for(int i=1+(l&1);i<=t;++i)printf("%d",a[i]);
    puts("");
    return 0;
}

E - Sinking Land

有一个\(H\times W\)的岛屿,周围被大海环绕。
这个岛屿可以被分成\(H\times W\)\(1\times 1\)的方块,\((i,j)\)方块的高度是\(A_{i,j}\)
\(i\)时刻,海平面高度是\(i\),如果一个方块与海相邻且高度不超过海平面,则会被淹没。
给定\(Y\),回答\(1-Y\)时刻,每个时刻还未被淹没的方块数量。

把所有和海面相邻的方块给丢进队列里面BFS,每次暴力枚举时间。这样子时间复杂度是\(O(Y\times 2(H+W))\),复杂度的数量级其实是没有问题的,但是常数比较大,可能无法通过。

用优先队列优化上述过程,每次取最接近被淹没的方块出来,这样子可以优化掉时间这一维度,可以做到\(O(HW)\)

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
using namespace std;
struct Node
{
    int x,y,t;
    bool operator<(const Node &a)const{
        return t>a.t;
    }
};
priority_queue<Node> Q;
const int MAX=1005;
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int d[4][2]={0,1,0,-1,1,0,-1,0};
int H,W,Y,A[MAX][MAX];
bool vis[MAX][MAX];
int ans[100100];
int main()
{
    H=read();W=read();Y=read();
    for(int i=1;i<=H;++i)
        for(int j=1;j<=W;++j)
            A[i][j]=read();
    for(int i=1;i<=H;++i)
        for(int j=1;j<=W;++j)
            vis[i][j]=false;
    for(int i=1;i<=H;++i)
        for(int j=1;j<=W;++j)
            if(i==1||j==1||i==H||j==W)
                vis[i][j]=true,Q.push((Node){i,j,A[i][j]});
    int T=0;
    while(!Q.empty())
    {
        Node now=Q.top();
        Q.pop();
        int x=now.x,y=now.y,t=now.t;
        T=max(T,t);
        ans[T]++;
        for(int i=0;i<4;++i)
        {
            int nx=x+d[i][0];
            int ny=y+d[i][1];
            if(nx>=1&&nx<=H&&ny>=1&&ny<=W)
                if(!vis[nx][ny])
                {
                    vis[nx][ny]=true;
                    Q.push((Node){nx,ny,A[nx][ny]});
                }
        }
    }
    for(int i=1;i<=Y;++i)ans[i]+=ans[i-1];
    for(int i=1;i<=Y;++i)printf("%d\n",H*W-ans[i]);
    return 0;
}

F - Palindromic Expression

给定一个数,问是否存在一个因数分解的方法,使得分解的结果可以列为一个只包含数字1-9*回文串。

暴力搜索!
如果当前的数字\(N\)自己本身就是一个不含零的回文数,那么直接返回。
否则的话,需要找到一对回文质因数,直接暴力枚举因数,检查是否有回文因数,如果有,那么递归处理即可。

#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
using namespace std;
#define ll long long 
ll N;
string dfs(ll N)
{
    string s=to_string(N);
    string s_rev=s;
    reverse(s_rev.begin(),s_rev.end());
    int l=s.length();
    bool zero_flag=false;
    for(int i=0;i<l;++i)if(s[i]=='0')zero_flag=true;
    if(!zero_flag&&s==s_rev)return s;
    for(int i=2,l=sqrt(N);i<=l;++i)
        if(N%i==0)
        {
            bool flag=true;
            int t=i,j=0;
            while(t)
            {
                if(t%10==0)flag=false;
                t/=10;
            }
            t=i;
            if(!flag)continue;
            while(t)j=j*10+t%10,t/=10;
            if((N/i)%j==0)
            {
                string ret=dfs(N/i/j);
                if(ret!="")
                    return to_string(i)+"*"+ret+"*"+to_string(j);
            }
        }
    return "";
}
int main()
{
    cin>>N;
    string ret=dfs(N);
    if(ret!="")cout<<ret<<endl;
    else cout<<-1<<endl;
    return 0;
}

G - Dynamic Scheduling

给定两个长度为\(n\)的序列D和P。
\(Q\)个操作,每个操作形如c x y,将\(D_c\)改为\(x\),将\(P_c\)改为\(y\)
每次修改完成之后,回答如下问题的答案:
\(n\)个任务,每天可以做一个任务,如果一个任务在\(D_i\)天前被解决,则可以获得奖励\(P_i\)。问可以得到的最大奖励。

模拟费用流。用线段树维护区间堆进行贪心。

posted @ 2024-07-21 20:54  小蒟蒻yyb  阅读(121)  评论(0编辑  收藏  举报