codeforces round236 DIV2

P1:Nuts

直接贪心...由于数量不是很大,枚举也行..

#include <iostream>

using namespace std;

int k,a,b,v;
int main()
{
    cin>>k>>a>>b>>v;
    int num=a/v;
    if (a%v) num++;
    int ans=0;
    int nw=0;
    while(b>0 && nw<num)
    {
        if (b>=k-1)
        {
        b-=(k-1);
        ans++;
        nw+=k;
        }
        else
        {
            ans++;
            nw+=(b+1);
            b=0;
        }
    }
    if (nw<num) ans+=(num-nw);
    cout<<ans<<endl;
    return 0;
}

P2: Trees in a Row

枚举第一棵树的高度,然后就可以扩展出所有树应有的高度了,记录一下每次需要调整的棵树,求一个最小值就行。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
int n,m,k;
int a[2020];
int cnt[2020];
bool f[2020];
int op[2020],x[2020],y[2020];
int b[2020];
int main()
{
//    freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&k);
    for(int i=0; i<n; i++)
    scanf("%d",&a[i]);
    int p=0,q=0,mx=99999;
    for (int i=1; i<=1000; i++)
    {
        p=0;
        memcpy(b,a,sizeof b);
        if (i!=a[0])
        {
            p++;
            b[0]=i;
        }

        for (int j=1; j<n; j++)
        if (b[j]-b[j-1]!=k)
        {
            p++;
            b[j]=k+b[j-1];
        }
        if (p<mx)
        {
            mx=p;
            q=i;
        }
    }
    printf("%d\n",mx);
    if (a[0]!=q)
    {
        if (a[0]>q) printf("- ");
        else printf("+ ");
        printf("%d %d\n",1,abs(a[0]-q));
        a[0]=q;
    }
    for (int i=1; i<n; i++)
    {
        if (a[i]-a[i-1]!=k)
        {
            int t=k+a[i-1];
            if (t>a[i]) printf("+ ");
            else printf("- ");
            printf("%d %d\n",i+1,abs(t-a[i]));
            a[i]=t;
        }
    }

    return 0;
}

P3: Searching for Graph

这题刚读题时的思路是把这2*n+p条变平均分到所有点上,后来换观察了下样例,好像有规律...从1开始枚举点i,在i和所有大于i的点直接连边,指导总边数达到2*n+p...我也不是很明白为什么这么做就是对的..但他就是过了...

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
int tt;
int main()
{
    int n,p;
    cin>>tt;
    while(tt--)
    {
        cin>>n>>p;
        int ct=0;
        p=2*n+p;
        bool ok=true;
        for (int i=1; i<=n&&ok; i++)
        for (int j=i+1; j<=n; j++)
        {
           cout<<i<<" "<<j<<endl;
           ct++;
           if (ct>=p)
           {
               ok=false;
               break;
           }
        }
    }
    return 0;
}

P4: Upgrading Array

       把题意转化一下,大致就是给n个数,m个坏质数,每个数的分数等于他的所有质因子中好因子数-坏因子数。现在可以多次选择前k个数,让这些数全部除以他们的最大公约数,求调整之后这n个数能达到的最大分数是多少。从千神那里听了一种贪心的思路...先处理一下前i项的gcd保存起来,然后从后向前枚举,枚举到第k个数时,前查一下前k个数的GCD的分数是否小于零,小于就可以除掉这个GCD了,扫一遍就是最后的答案...

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=5050;
int g[maxn];
int n,m,k;
int a[maxn],b[maxn];
int d[maxn];
const int N=201000;
int prime[N], np;
bool vis[N];
void ss()
{
    np = 0;
    memset(vis, 0, sizeof(vis));
    for(int i = 2; i < N; ++i)
    {
        if (!vis[i])
        {
            prime[np++] = i;
            for(int j = i+i; j < N; j +=i) vis[j] = 1;
        }
    }
}
int gcd(int x,int y)
{
    if (y==0) return x;
    return gcd(y,x%y);
}
int main()
{
//    freopen("in.txt","r",stdin);
    ss();
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++)
    scanf("%d",&a[i]);
    map<int,int>bad;
    for (int i=1; i<=m; i++)
    scanf("%d",&b[i]),bad[b[i]]=1;
    g[1]=a[1];
    for (int i=2; i<=n; i++)
    {
        g[i]=gcd(g[i-1],a[i]);
    }
//    for (int i=1; i<=n; i++)
//    cout<<g[i]<<" ";
//    cout<<endl;

    ll ans=0;
    for (int i=1; i<=n; i++)
    {
        int tp=a[i];
        for (int j=0; j<np&&prime[j]<=tp;j++)
        {
            while(tp>1 && tp%prime[j]==0)
            {
                if (bad.find(prime[j])!=bad.end())
                {
                    ans--;
                }
                else  ans++;
                tp/=prime[j];
            }
        }
         if (tp>1)
            {
                if (bad.find(tp)!=bad.end()) ans--;
                else ans++;
            }
    }


    ll last=0;
    for (int i=n; i>=1; i--)
    {
        int tp=g[i];
        ll pt=0;
        for (int j=0; j<np&&prime[j]<=tp; j++)
        {
             while(tp>1 && tp%prime[j]==0)
             {
                 if (bad.find(prime[j])!=bad.end())
                 {
                     pt--;
                 }
                 else pt++;
                 tp/=prime[j];
             }
        }
        if (tp>1)
        {
            if (bad.find(tp)!=bad.end()) pt--;
            else pt++;
        }
        if (pt-last<0)
        {
            ans-=(pt*(ll)i);
            ans+=(last*ll(i));
            last=pt;
        }
    }
        cout<<ans<<endl;
    return 0;
}

P5: Strictly Positive Matrix

给一个矩阵A,保证每个元素大于等于0,并且对角线上的元素和一定大于0,判断是否存在k>0使得A^k的元素全部都是大于0的。

还剩15分钟的时候弃疗去睡觉了= =结果刚关上电脑就反应过来怎么写了...果然是应该坚持到最后的啊= =.....对于一个矩阵,我们可以把它看做一个有向图的邻接矩阵,那么A^k中A[i,j]其实就是从点i到j经过A[i,j]步可达。原题就可以等价于判断原图是否是强连通图,因为对角线上元素的和大于0,说明至少存在一个自环,那么在全图强连通的情况下,我就可以保证任意两点之间都是可以通过任意步可达的,也就是A^k的所有元素均大于0.

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
bool g[2020][2020];
int n,m,k;
bool vis[2020];
void dfs1(int v,int fa)
{
    vis[v]=true;
    for (int i=1; i<=n; i++)
    {
        if (i!=v && i!=fa && !vis[i] && g[v][i])
        {
            dfs1(i,v);
        }
    }
}
void dfs2(int v,int fa)
{
    vis[v]=true;
    for (int i=1; i<=n; i++)
    {
        if (i!=v && i!=fa && !vis[i] && g[i][v])
        {
            dfs2(i,v);
        }
    }
}
int main()
{
//    freopen("in.txt","r",stdin);
    scanf("%d",&n);
    memset(g,false,sizeof g);
    for (int i=1; i<=n; i++)
     for (int j=1; j<=n; j++)
     {
        scanf("%d",&k);
        if (k) g[i][j]=1;
        else g[i][j]=0;
     }
     memset(vis,false,sizeof vis);
     dfs1(1,-1);
     bool ok=true;
     for (int i=1; i<=n; i++)
     if (!vis[i])
     {
         ok=false; break;
     }
     if (ok)
     {
         memset(vis,0,sizeof vis);
         dfs2(1,-1);
         for (int j=1; j<=n; j++)
         {
             if (!vis[j])
             {
                 ok=false; break;
             }
         }
     }
     if (ok) puts("YES");
     else puts("NO");

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值