Codeforces Round #236 (Div. 1) A,B,C

本文解析了三道ACM竞赛题目,包括简单的图遍历、质因数分解及矩阵连通性判断等算法,提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A题:
水题不用说,乱搞搞就过了。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int map[51][51];
int main()
{
    int i,j,a,b,c,d,T,n,p;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&p);
        memset(map,0,sizeof(map));
        for(i=1;i<=n;i++)
        {
            a=i;b=i+1;
            c=i;d=i+2;
            if(b>n)b=b-n;
            if(d>n)d=d-n;
            map[a][b]=map[b][a]=1;
            map[c][d]=map[d][c]=1;
        }
        int ad=3;
        while(1)
        {
            if(p==0)break;
            for(i=1;i<=n;i++)
            {
                a=i;
                b=i+ad;
                if(b>n)b=b-n;
                if(map[a][b]==0)
                {
                    map[a][b]=map[b][a]=1;
                    p--;
                    if(p==0)break;
                }
            }
            if(p==0)break;
            ad++;
        }
        for(i=1;i<=n;i++)
        {
            for(j=i+1;j<=n;j++)
            {
                if(map[i][j])
                {
                    cout<<i<<" "<<j<<endl;
                }
            }
        }
    }
    return 0;
}


B题:
由题意可知:
f(x):x所有的因子,如果某个因子为坏素数,结果-1,如果为好素数,结果+1;
a数组中的数可以做无数次操作。
假如两次操作i,j。如果i先操作,j后操作。那么i操作的r一定大于j操作的r。
那么就可以从a数组的后面往前面搜。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int as[110000],prime[110000];
int num,N;
void Prime()
{
    memset(as, 0, sizeof(as));
    int i, j;
    num=0;
    for(i = 2; i < N; ++i)
    {
        if(!(as[i])) prime[num++] = i;
        for(j = 0; (j<num && i*prime[j]<N); ++j)
        {
            as[i*prime[j]] = 1;
            if(!(i%prime[j])) break;
        }
    }
}
int gcd(int n,int m)
{
    if(n<m)swap(n,m);
    if(m==0)return n;
    return gcd(m,n%m);
}
int a[10000];
int b[10000];
int g[10000];
int dp[2][10000];
int n,m;
int inb(int x)
{
    int l=1;
    int r=m+1;
    int mid=(l+r)/2;
    while(l<r)
    {
        if(b[mid]>x)r=mid;
        if(b[mid]<x)l=mid+1;
        if(b[mid]==x)return 1;
        mid=(l+r)/2;
    }
    return 0;
}
int dos(int x)
{
    int st,ans,ps,i;
    st=ans=0;
    int sqx;
    for(i=0; i<num; i++)
    {
        sqx=sqrt(x);ps=prime[i];
        if(ps>sqx)break;
        st=0;
        if(x%ps==0)
        {
            while(x%ps==0)
            {
                x=x/ps;
                st++;
            }
            if(inb(ps))ans-=st;
            else ans+=st;
        }
    }
    if(x!=1)
    {
        ps=x;st=1;
        if(inb(ps))ans-=st;
        else ans+=st;
    }
    return ans;
}
int main()
{
    int T,i,j;
    N=100000;
    Prime();
    while(~scanf("%d%d",&n,&m))
    {
        memset(dp,0,sizeof(dp));
        for(i=1; i<=n; i++)scanf("%d",&a[i]);
        for(j=1; j<=m; j++)scanf("%d",&b[j]);
        sort(b+1,b+m+1);
        g[1]=a[1];
        for(i=2; i<=n; i++)
        {
            g[i]=gcd(g[i-1],a[i]);
        }
        for(i=1;i<=n;i++)
        {
            dp[0][i]=dp[0][i-1]+dos(a[i]);
        }
        int maxx=0;
        maxx=dp[0][n];
        int t=1;
        for(i=n;i>=1;i--)
        {
            int kk=g[i]/t;
            int pp=dos(kk);
            if(pp<0)
            {
                t=g[i];
                maxx-=i*pp;
            }
        }
        cout<<maxx<<endl;
    }
    return 0;
}


C题:
从代码上来讲,我感觉c题比b题好写多了。。。
C题给你一个矩阵。问你矩阵的任意次方之后,会不会出现矩阵上的所有的数字都大于0.
一个矩阵a[i][j]>0,代表ij之间可走。
那么本题就化身为给定一个图,问,任意两点之间是否可达。
那么本题就化身为给定一个图,然后tarjan算法求缩点,看最后是否会缩成一个点。
By rowanhao, contest: Codeforces Round #236 (Div. 1), problem: (C) Strictly Positive Matrix, Accepted, #
 #include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<stack>
using namespace std;
#define maxn 3001
struct list
{
    int u;
    int v;
    int next;
}edge[4400000];
int head[4400000];
int low[maxn];
int dnf[maxn];
int instack[maxn];
int times;
int num;
int nums;
int n;
void init()
{
    memset(head,-1,sizeof(head));
    num=0;
    nums=0;
    times=0;
    memset(dnf,0,sizeof(dnf));
    memset(instack,0,sizeof(instack));
    memset(low,0,sizeof(low));
}
void add(int u,int v)
{
    edge[num].u=u;
    edge[num].v=v;
    edge[num].next=head[u];
    head[u]=num++;
}
stack<int>qq;
void tarjan(int x)
{
    dnf[x]=low[x]=times++;
    instack[x]=1;
    qq.push(x);
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int y=edge[i].v;
        if(!dnf[y])
        {
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(instack[y])
        {
            low[x]=min(low[x],dnf[y]);
        }
    }
    if(low[x]==dnf[x])
    {
        int y=-1;
        while(x!=y)
        {
            y=qq.top();
            qq.pop();
            instack[y]=0;
        }
        nums++;
    }
}
int main()
{
    int i,j,x;
    while(~scanf("%d",&n))
    {
        init();
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%d",&x);
                if(x)
                {
                    add(i,j);
                }
            }
        }
        for(i=1;i<=n;i++)
        {
            if(!dnf[i])
            {
                tarjan(i);
            }
        }
        if(nums>1)
        {
            cout<<"NO"<<endl;
        }
        else cout<<"YES"<<endl;
    }
}































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值