【周赛题解】三

A. Playing with Paper

解法用辗转相除法,一边求出最大公约数,一边求出可分割的正方形的数量。

#include<stdio.h>
#include<math.h>
using namespace std;
typedef long long ll;
ll ans=0;
ll gcd(ll a,ll b)
{
    if(b==0) return a;
    else
    {
        ans+=a/b;
        return gcd(b,a%b);
    }
}
int main()
{
    ll a,b;
    scanf("%I64d%I64d",&a,&b);
    gcd(a,b);
    printf("%I64d\n",ans);
    return 0;
}

B. Error Correct System

用二维数组标记一下转换表再查找就可以啦

a[i][j]表示字符i转换为字符j的第一个位置

如果a[i][j]和a[j][i]都有需要转换的话,就交换这两个位置,否则查找如a[i][j],a[j][k]的形式交换,否则不能交换。

#include<stdio.h>
#include<math.h>
#include<string.h>
using namespace std;
int len;
char s1[200005],s2[200005];
int a1[26][26];
int main()
{
    int i,j,ii;
    memset(a1,-1,sizeof(a1));
    scanf("%d",&len);
    getchar();
    gets(s1);
    gets(s2);
    int k=0;
    for(i=0;i<len;i++)
    {
        if(s1[i]!=s2[i])
        {
            a1[s1[i]-'a'][s2[i]-'a']=i;
            k++;
        }
    }
    int ans1=-1,ans2=-1;
    /*for(i=0;i<len;i++)
    {
        if(a1[i]&&a2[i])
        {
            ans1=a1[i];
            ans2=a2[i];
        }
    }*/
    for(i=0;i<26;i++)
    {
        for(j=i+1;j<26;j++)
        {
            if(a1[i][j]!=-1&&a1[j][i]!=-1)
            {
                ans1=a1[i][j];ans2=a1[j][i];
                break;
            }
        }
        if(j<26) break;
    }
    if(ans1!=-1)
    {
        printf("%d\n",k-2);
        printf("%d %d\n",ans1+1,ans2+1);
    }
    else
    {
        for(i=0;i<26;i++)
        {
            for(j=0;j<26;j++)
            {
                if(a1[i][j]!=-1)
                {
                    for(ii=0;ii<26;ii++)
                    {
                        if(a1[j][ii]!=-1)
                        {
                            ans1=a1[i][j];
                            ans2=a1[j][ii];
                            break;
                        }
                    }
                    if(ii<26) break;
                }
            }
            if(j<26) break;
        }
        if(ans1!=-1)
        {
            printf("%d\n",k-1);
            printf("%d %d\n",ans1+1,ans2+1);
        }
        else
        {
            printf("%d\n",k);
            printf("-1 -1\n");
        }
    }
    return 0;
}

  

C. Glass Carving

本题要使用特殊的数据结构。

维护横向和纵向的最大宽度,查询时想乘即可。

#include<stdio.h>
#include<math.h>
#include<set>
#include<map>
using namespace std;
set<int> H,V;
map<int,int> HH,VV;
int main()
{
    int w,h,n,z;
    char c;
    scanf("%d%d%d",&w,&h,&n);
    H.insert(0);
    H.insert(h);
    V.insert(0);
    V.insert(w);
    HH[h]=1;
    VV[w]=1;
    while(n--)
    {
        int w;
        getchar();
        scanf("%c%d",&c,&z);
        if(c=='H')
        {
            H.insert(z);
            {
                int l,r;
                set<int>::iterator it;
                it=H.find(z);
                it--;
                l=*it;
                it++;
                it++;
                r=*it;
                HH[r-l]--;
                if(HH[r-l]==0)
                {
                    HH.erase(r-l);
                }
                HH[z-l]++;
                HH[r-z]++;
                printf("%I64d\n",(long long)(HH.rbegin()->first) *(VV.rbegin()->first) );
            }
        }
        else
        {
            V.insert(z);
            {
                int l,r;
                set<int>::iterator it;
                it=V.find(z);
                it--;
                l=*it;
                it++;
                it++;
                r=*it;
                VV[r-l]--;
                if(VV[r-l]==0)
                {
                    VV.erase(r-l);
                }
                VV[z-l]++;
                VV[r-z]++;
                printf("%I64d\n",(long long)(HH.rbegin()->first) *(VV.rbegin()->first) );
            }
        }
    }
    return 0;
}

  

D. Clique Problem

将问题转换,每个点的x和w值可以转换成区间(x-w,x+w),然后求出不想交的区间的最大个数即答案。

求法是贪心,每次都选择右边界最小且和之前的区间不想交的区间即可。

#include<stdio.h>
#include<math.h>
#include<map>
#include<algorithm>
using namespace std;
typedef pair<int,int> P;
P p[200005];
int main()
{
    int len,i,x,w;
    scanf("%d",&len);
    for(i=0;i<len;i++)
    {
        scanf("%d%d",&x,&w);
        p[i].first=x+w;
        p[i].second=x-w;
    }
    int to=-1000000005,ans=0;
    sort(p,p+len);
    for(i=0;i<len;i++)
    {
        if(p[i].second>=to)
        {
            ans++;
            to=p[i].first;
        }
    }
    printf("%d\n",ans);
    return 0;
}

  

E. Data Center Drama

图论题。没A。。

先判断图是否存在欧拉回路,若不存在则补充边,(度为奇数个的点要补充)。

求出图的欧拉回路,然后顺着路径翻转编号为奇数(或偶数)的边,最后如果总边数是奇数个,就在出发点加一个自环。

posted on 2015-03-24 21:32  T^T  阅读(194)  评论(0编辑  收藏  举报

导航