TJUACM假期集训个人赛(一)(AtCoder ABC 307)

文章介绍了在AtCoder等编程竞赛中,针对不同类型的题目(如数列求和、字符串匹配、图形拼接、括号序列处理和数组问题)的解题思路和C++代码实现,包括暴力求解、动态规划和最短路径算法的应用。
摘要由CSDN通过智能技术生成

这次考的是 A t C o d e r AtCoder AtCoder的题 发挥不是很好
用洛谷当题面了 还能方便点

A

直接七天一求和就行

#include<bits/stdc++.h>
#define reg register
using namespace std;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}

int n,a,x;
int main(){
    read(n);
    for(int i=1;i<=n;i++){
        x=0;
        for(int j=1;j<=7;j++)read(a),x+=a;
        printf("%d ",x);
    }
    puts("");
}

B

100 100 100个字符串 暴力两个两个判断即可

#include<bits/stdc++.h>
#define reg register
using namespace std;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
char s[110][110],ss[110];
int n,l[110];
bool pd(char str[],int len){
    for(int l=0,r=len-1;l<=r;l++,r--){
        if(str[l]!=str[r])return false;
    }
    return true;    
}
int main(){
    read(n);
    for(int i=1;i<=n;i++)cin.getline(s[i],sizeof s[i]),l[i]=strlen(s[i]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(j==i)continue;
            for(int k=0;k<l[i];k++)ss[k]=s[i][k];
            for(int k=0;k<l[j];k++)ss[k+l[i]]=s[j][k];
            if(pd(ss,l[i]+l[j])){
                puts("Yes");
                return 0;
            }
        }
    }
    puts("No");
}

C

因为拼接之后最大的图形也只有 10 × 10 10×10 10×10,所以直接将 A , B A,B A,B暴力移动到所有位置,一一判断,时间复杂度 O ( 1 0 6 ) O(10^6) O(106)

#include<bits/stdc++.h>
#define reg register
#define N 100
using namespace std;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
int ha,wa,hb,wb,hx,wx,a[N][N],b[N][N],x[N][N];
bool check(int ax, int ay, int bx, int by){
    for(int i=1;i<=ha;i++){
        for(int j=1;j<=wa;j++){
            if(!((i+ax>0&&i+ax<=hx)&&(j+ay>0&&j+ay<=wx))&&a[i][j])return false;
            if(((i+ax>0&&i+ax<=hx)&&(j+ay>0&&j+ay<=wx))&&a[i][j])
                if(!x[i+ax][j+ay])return false;
        }
    }
    for(int i=1;i<=hb;i++){
        for(int j=1;j<=wb;j++){
            if(!((i+bx>0&&i+bx<=hx)&&(j+by>0&&j+by<=wx))&&b[i][j])return false;
            if(((i+bx>0&&i+bx<=hx)&&(j+by>0&&j+by<=wx))&&b[i][j])
                if(!x[i+bx][j+by])return false;
        }
    }
    for(int i=1;i<=hx;i++)
        for(int j=1;j<=wx;j++)
            if(x[i][j]&&!a[i-ax][j-ay]&&!b[i-bx][j-by])return false;
    return true;
}
int main(){
    read(ha),read(wa);
    for(reg int i=1;i<=ha;i++){
        for(reg int j=1;j<=wa;j++){
            char chr=getchar();
            while(chr!='.'&&chr!='#')chr=getchar();
            if(chr=='#')a[i][j]=1;
        }
    }
    read(hb),read(wb);
    for(reg int i=1;i<=hb;i++){
        for(reg int j=1;j<=wb;j++){
            char chr=getchar();
            while(chr!='.'&&chr!='#')chr=getchar();
            if(chr=='#')b[i][j]=1;
        }
    }
    read(hx),read(wx);
    for(reg int i=1;i<=hx;i++){
        for(reg int j=1;j<=wx;j++){
            char chr=getchar();
            while(chr!='.'&&chr!='#')chr=getchar();
            if(chr=='#')x[i][j]=1;
        }
    }
    for(int ai=-10;ai<=10;ai++){
        for(int aj=-10;aj<=10;aj++){
            for(int bi=-10;bi<=10;bi++){
                for(int bj=-10;bj<=10;bj++){
                    if(check(ai,aj,bi,bj)){
                        puts("Yes");
                        return 0;
                    }
                }
            }
        }
    }
    puts("No");
}

D

模拟,把两个括号之间没有括号的子字符串删除即可,考场上因为这题题面没看懂浪费了一个小时时间

#include<bits/stdc++.h>
#define reg register
using namespace std;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
stack<char> s;
stack<char> ans;
int n,lst,eps[200002],nxt[200002];
char chr;
int main(){
    read(n);
    for(int i=1;i<=n;i++){
        chr=getchar();
        while(chr!='('&&chr!=')'&&(chr<'a'||chr>'z'))chr=getchar();
        if(chr=='('){
            nxt[i]=lst;lst=i;
            s.push(chr);
        }
        else if(chr>='a'&&chr<='z')s.push(chr);
        else if(chr==')'){
            if(lst){
                for(int j=lst;j<=i-1-eps[lst]&&!s.empty();j++){
                    s.pop();
                }
                eps[nxt[lst]]+=(i-lst+1);
                lst=nxt[lst];
            }   
            else{
                s.push(chr);
                lst=0;
            }
        }
    }
    while(!s.empty()){
        ans.push(s.top());
        s.pop();
    }
    while(!ans.empty()){
        putchar(ans.top());
        ans.pop();
    }
    puts("");
}

E

d p , dp, dp, d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示第 i i i个人与第一个人的数不相同,并且相邻两人的也不相同的方案数, d p [ i ] [ 1 ] dp[i][1] dp[i][1]表示只有第 i i i个人与第一个人的数相同,其他都不相同的方案数
首先考虑 d p [ i ] [ 1 ] , dp[i][1], dp[i][1], i i i个人与第一个人可以看成一个人,所以 d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] dp[i][1]=dp[i-1][0] dp[i][1]=dp[i1][0]
再考虑 d p [ i ] [ 0 ] , dp[i][0], dp[i][0]对第 i − 1 i-1 i1个人分类讨论,如果与第一个人相同,那第 i i i个人有 m − 1 m-1 m1种情况,去掉第 i i i个人,就变成了 d p [ i − 1 ] [ 1 ] dp[i-1][1] dp[i1][1]
如果与第一个人不同,那么第 i i i个人有 m − 2 m-2 m2种情况,去掉第 i i i个人,就变成了 d p [ i − 1 ] [ 0 ] dp[i-1][0] dp[i1][0]
所以转移式为 d p [ i ] [ 0 ] = ( m − 1 ) d p [ i − 1 ] [ 1 ] + ( m − 2 ) d p [ i − 1 ] [ 0 ] dp[i][0]=(m-1)dp[i-1][1]+(m-2)dp[i-1][0] dp[i][0]=(m1)dp[i1][1]+(m2)dp[i1][0]
d p [ i ] [ 1 ] = d p [ i − 1 ] [ 1 ] dp[i][1]=dp[i-1][1] dp[i][1]=dp[i1][1]
最后输出 d p [ n ] [ 0 ] dp[n][0] dp[n][0]即可。

#include<bits/stdc++.h>
#define reg register
#define N int(1e6+10)
using namespace std;
typedef long long ll;
const ll mod=998244353;
ll qpow(ll x, ll y){
    ll re=1;
    while(y){
        if(y&1)(re*=x)%=mod;
        (x*=x)%=mod,y>>=1;
    }
    return re;
}
ll n,m,dp[N][2];
int main(){
    cin>>n>>m;
    dp[1][1]=m;
    for(int i=2;i<=n;i++){
        dp[i][0]=((m-1)*dp[i-1][1]%mod+(m-2)*dp[i-1][0]%mod)%mod;
        dp[i][1]=dp[i-1][0];
    }
    cout<<dp[n][0]<<endl;
}

F

利用最短路的思想,每次把中毒的点距离设为 0 0 0,并更新相邻的点的 d i s dis dis数组,并放进小根堆中,每一天把堆中距离小于 x x x的拿出来更新,距离设为 0 0 0,并更新相邻的点,同时记录感染时间即可,因为每个点会被第一次设距离,第二次中毒更新,因此最多会遍历两次,时间复杂度就是最短路的时间复杂度,即为 O ( n l o g m ) O(nlog_m) O(nlogm)

#include<bits/stdc++.h>
#define reg register
#define N 300030
using namespace std;
typedef long long ll;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
struct edges{
    int to,val,nxt;
}edge[N<<1];
struct node{
    int id;
    ll d;
    node(int x, ll y){
        id=x,d=y;
    }
    bool operator <(const node &p) const {
        return p.d<d;
    }
};
int n,u,v,w,m,k,x,t,pnt,head[N],cnt,vis[N],newin[N];
ll dis[N];
inline void addedge(int u, int v, int w){
    edge[++cnt].to=v,edge[cnt].nxt=head[u],head[u]=cnt,edge[cnt].val=w;
}
inline void superadd(int u, int v, int w){
    addedge(u,v,w),addedge(v,u,w);
}
int main(){
    read(n),read(m);
    for(reg int i=1;i<=m;i++)read(u),read(v),read(w),superadd(u,v,w);
    read(k);
    memset(dis,0xf,sizeof dis);
    memset(vis,-1,sizeof vis);
    priority_queue<node> q;
    for(int j=1;j<=k;j++){
        read(u);
        vis[u]=0;dis[u]=0LL;
        q.push(node(u,0LL));
        for(int i=head[u];i;i=edge[i].nxt){
            int vv=edge[i].to;
            if(dis[vv]>edge[i].val){
                dis[vv]=edge[i].val;
                q.push(node(vv,dis[vv]));
            }
        }
    }
    read(t);
    for(int ii=1;ii<=t;ii++){
        pnt=0;
        read(x);
        while(!q.empty()){
            node now=q.top();
            if(dis[now.id]>x)break;
            q.pop();
            if(dis[now.id]!=now.d||vis[now.id]!=-1)continue;
            vis[now.id]=ii;newin[++pnt]=now.id;
            for(int i=head[now.id];i;i=edge[i].nxt){
                int vv=edge[i].to;
                if(dis[vv]>dis[now.id]+edge[i].val){
                    dis[vv]=dis[now.id]+edge[i].val;
                    q.push(node(vv,dis[vv]));
                }
            }
        }
        for(int j=1;j<=pnt;j++){
            for(int i=head[newin[j]];i;i=edge[i].nxt){
                int vv=edge[i].to;
                if(dis[vv]>edge[i].val){
                    dis[vv]=edge[i].val;
                    q.push(node(vv,dis[vv]));
                }
            }
        }
    }
    for(int i=1;i<=n;i++)printf("%d\n",vis[i]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值