Codeforces Gym100935

题目链接CodeForces Gym100935

A - Time

【题意】
给出两个时间,判断时间是否相等
【思路】
直接模拟,全部转成s
【Code】

#include<cstdio>
int main()
{
    int T,x,y,z,s1,s2;
    scanf("%d",&T);
    for (int Case=1;Case<=T;Case++)
    {
        scanf("%d%d%d",&x,&y,&z);
        s1=x*3600+y*60+z;
        scanf("%d%d%d",&x,&y,&z);
        s2=x*3600+y*60+z;
        printf("Case %d: ",Case);
        if (s1==s2) printf("Yes\n");
        else printf("No\n");
    }
}

B - Weird Cryptography

【题意】
给定N个字符串,你可以把他们组成若干个集合,每个集合不能有相同的字符串。保证不相同的字符串不超过9,让所有集合的大小组成一个十进制数字并使这个数字最小, 求出这个数。
【思路】
贪心:
首先, 要让数字最小, 就必须让这个数位数最少。然后就是肯定是要让最大的那个集合尽可能的大,最小的那个集合尽可能的小。
先用map 对每个字符串标记一下,记录一下每个元素出现的次数。
然后枚举每一个字符串,让字符串从后往前放完,所有字符串中出现次数最多的就是最后组合成的数的位数。
【Code】

#include<cstdio>
#include<iostream>
#include<string>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
string st[10010];
int a[10010];
map<string,int> Map;
int main()
{
    int n,T=0;
    while (~scanf("%d",&n)&&(n))
    {
        Map.clear();
        memset(a,0,sizeof(a));
        int m=0;
        for (int i=1;i<=n;i++)
        {
            cin>>st[i];
            Map[st[i]]++;
        }
        map<string,int> ::iterator iter;
        for (iter=Map.begin();iter!=Map.end();iter++)
        {
            int i= iter->second;
            m=max(m,i);
            for (int k=1;k<=i;k++)
                a[k]++;
        }
        printf("Case %d: ",++T);
        for (int k=m;k>=1;k--)
            printf("%d",a[k]);
        printf("\n");
    }
    return 0;
}

C - OCR

【题意】
给你一个二维点阵,判断是”0”还是”8”
【思路】
模拟水题
【Code】

#include<cstdio>
#include<cstring>
int n,m,x1,y1,x2,y2;
char a[22][22];
void findst()
{
    for (int i=0;i<n;i++)
        for (int j=0;j<m;j++)
            if (a[i][j]=='*')
    {
        x1=i;y1=j;
        return;
    }
}
void finded()
{
    for (int i=n-1;i>=0;i--)
        for (int j=n-1;j>=0;j--)
            if (a[i][j]=='*')
    {
        x2=i;y2=j;
        return;
    }
}
bool check()
{
     for (int i=x1+1;i<x2;i++)
        for (int j=y1+1;j<y2;j++)
            if (a[i][j]=='*') return true;
    return false;
}
int main()
{
    int T;
    scanf("%d",&T);
    for (int Case=1;Case<=T;Case++)
    {
        scanf("%d %d",&n,&m);
        for (int i=0;i<n;i++)
            scanf("%s",a[i]);
        findst();
        finded();
        //printf("%d %d %d %d \n",x1,y1,x2,y2);
        if (check()) printf("Case %d: Eight\n",Case);
        else printf("Case %d: Zero\n",Case);
    }
}

D - Enormous Carpet

【题意】
求A*(K^N)% mod[i]。
【思路】
裸的快速幂
【Code】

#include <cstdio>
typedef long long LL;
LL mo[110];
LL fastpow(LL a,LL b,LL c,LL mod){
    LL res=a;
    while(c){
        if(c&1)
            res=(res*b) % mod;
        b = (b * b) % mod;
        c >>= 1LL;
    }
    return res % mod;
}
int main()
{
    int Case = 1;
    LL a,b,c;
    while(~scanf("%I64d%I64d%I64d", &a, &b, &c))
    {
        if(a==0 && b==0 && c==0)  break;
        int n;
        scanf("%d", &n);
        for (int i=0;i<n; i++) scanf("%I64d", &mo[i]);
        printf("Case %d:\n",Case++);
        for (int i=0;i<n-1; i++)
            printf("%I64d ", fastpow(c, b, a, mo[i]));
        printf("%I64d\n",fastpow(c, b, a, mo[n-1]));
    }
}

E - Pairs

【题意】
有5个有序数字(X1, X2, X3, X4, X5) ,他们两两组成可以组成10个数对。现在已知这每个数对中两个数之和,让你还原这5个数字。
【思路】
首先对这个10数字进行排序,然后
已经确定的是有(X1, X2) (X1, X3), (X3,X5), (X4,X5) 这四个数对 对应的和是多少。
然后只需要枚举 (X2, X3) 和 (X3, X4) 这两个数对的和就Ok了。
X[1] = (X1 + X2) + (X1 + X3) - (X2 + X3)
其他的同理。
【Code】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[6],f[11],s[11],d[6][6];
bool check()
{
    for (int i=1;i<=5;i++)
        if (a[i]<=0) return false;
    for (int i=2;i<=5;i++)
        if (a[i-1]>a[i]) return false;
    int k=0;
    for (int i=1;i<=4;i++)
        for (int j=i+1;j<=5;j++)
           f[k++]=a[i]+a[j];
    sort(f,f+10);
    for (int i=0;i<10;i++)
        if (s[i]!=f[i]) return false;
    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    for (int Case=1;Case<=T;Case++)
    {
        for (int i=0;i<10;i++) scanf("%d",&s[i]);
        sort(s,s+10);
        d[1][2]=s[0];d[1][3]=s[1];
        d[3][5]=s[8];d[4][5]=s[9];
        bool flag=false;
        for (int i=2;i<8;i++)
        {
            if (flag) break;
            d[2][3]=s[i];
            for (int j=7;j>i;j--)
            {
                d[3][4]=s[j];
                a[1]=d[1][2]+d[1][3]-d[2][3];
                if (a[1]%2==1) continue;
                a[1]/=2;
                a[5]=d[3][5]+d[4][5]-d[3][4];
                if (a[5]%2==1) continue;
                a[5]/=2;
                a[2]=d[1][2]-a[1];
                a[3]=d[2][3]-a[2];
                a[4]=d[4][5]-a[5];
                if (check())
                {
                    flag=true;
                    break;
                }
            }
        }
        sort(a+1,a+5+1);
        printf ("Case %d: %d %d %d %d %d\n",Case,a[1],a[2],a[3],a[4],a[5]);
    }
}

F - A Poet Computer

【题意】
给定N个单词,这些单词中,如果有三个或者三个以上单词尾部相同,则就定义为”Common Suffix”, 求”Common Suffix”最长的长度,以及出现的次数。
【思路】
将单词逆序加入到字典树中,然后直接统计就好了。
【Code】

这里写代码片

G - Board Game

【题意】
将1~16的数填到这个4*4的矩阵中,使每行的数字和相等,每列的数字和相等,行和列的数字和相等,已经填好7个数,让你补充此矩阵,输出一种字典序最小的方案.
【思路】
DFS.
【Code】

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
bool flag;
int Case=1;
int a[7][7];
bool v[17];
void dfs(int x,int y)
{
    if (flag) return;
    if (x>=1&&y==0)
    {
        int sum=0;
        for (int i=0;i<4;i++) sum+=a[x-1][i];
        if (sum!=34) return;
    }
    if( x==3&&y>=1)
    {
        int sum=0;
        for (int i=0;i<4;i++) sum+=a[i][y-1];
        if (sum!=34) return;
    }
    if (x==4)
    {
        printf("Case %d:\n",Case++);
        for (int i=0;i<4;i++)
        {
            for(int j=0;j<3;j++)
                printf("%d ",a[i][j]);
            printf("%d\n",a[i][3]);
        }
        flag=true;
    }
    if (a[x][y]==-1)
    {
        for(int i=1;i<=16;i++)
        {
            if(flag) return ;
            if (!v[i])
            {
                v[i]=true;
                a[x][y]=i;
                if (y<3) dfs(x,y+1);
                else dfs(x+1,0);
                v[i]=false;
                a[x][y]=-1;
            }
        }
    }
    else{
        if(y<3) dfs(x,y+1);
        else  dfs(x+1,0);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        flag=false;
        memset(a,0,sizeof(a));
        memset(v,0,sizeof(v));
        for (int i=0;i<4;i++)
            for (int j=0;j<4;j++)
            {
                scanf("%d",&a[i][j]);
                if(a[i][j]!=-1) v[a[i][j]]=true;
            }
        dfs(0,0);
    }
}

H - Bend Test

【题意】
有P部手机需要进行压力测试(每部手机的耐压值是一样的),压力值从1~M,(P∈[1, 50], M ∈[1, 1000]), 当压力值大于手机的耐压值时,这部手机就被摧毁了,不能继续进行测试了, 现在要你求出,在最坏的情况下,最少需要多少次可以测出压力值。
【思路】
做过了好几次的扔鸡蛋问题.
首先说一种O(n*m^2)的做法
状态: dp[i][j]表示N=i,M=j时,最多需要多少次测试。
状态转移方程:
如果我们一开始是在k层进行测试的,那么如果鸡蛋破碎了,我们的查找范围就变成k层一下的k-1层,当然此时鸡蛋数减少了,所以最终的步数应该为dp[i-1][k-1]+1;另外一种情况是鸡蛋没有碎的情况,我们要找的范围变成了k层以上的,所以最终需要dp[i][j-k]+1步。我们的目标就是要找到一个k,使得最坏情况下测试数最少,所以我们需要枚举k。代码如下:

 for (int i=2;i<=MAXN;i++)
     for (int j=2;j<=MAXM;j++)
         for (int k=1;k<j;k++)
              dp[i][j]=min(dp[i][j],max(dp[i-1][k-1]+1,dp[i][j-k]+1));

初始状态: N=1时,测试数为M;M=1,测试数为1;M=0,测试数为0;
//———————————————————-分割线—————————————————–
下面是用之前的算法解决dp[4,50]问题的递推结果表格(其中,行代表楼层数1~50,列代表鸡蛋数1~4),我们会发现,dp[2][36]=8,dp[2][37] = 9,那么是不是用2颗鸡蛋测试8次,最多只能解决36层楼问题,对于37层就无能为力了呢?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9 10 10 10 10 10
1 2 2 3 3 3 3 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7
1 2 2 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6

这里引出了一个问题:n个鸡蛋,测试m次(简记为f[n][m]),最大可以解决几层楼的问题,通过对递推结果表格的观察,我们可以得到如下结论

f[1][m] = m
f[n][n] = 2^n - 1
f[n][m] (n<=m) = f[m][m]
对于第二点,以f[4][4]为例,我们第1次在8楼扔下鸡蛋,如果碎了,则第二次在4楼扔下鸡蛋,否则在12楼扔下鸡蛋,对于在4楼扔下鸡蛋的情况,之后可以分别在2楼或者6楼扔下鸡蛋,如此进行,就可以找到答案楼层,方法与二分查找一样。例如答案楼层是5的情况,测试序列为8,4,6,5。

对于第三点,如果有5个鸡蛋让你测试3次,即使三次测试鸡蛋都碎了,剩下的2个鸡蛋也派不上用场,所以f[5][3]=f[3][3]

发现这些关系之后,我们似乎找到解决n个鸡蛋测试m次最大能够解决楼层数的方法。对于f[n][m] (n< m) 而言,对于其能够测试的最大楼层数k,我们可以构造这样的场景,将第一颗鸡蛋仍在楼层i,使得第i + 1层到第k层是f[n][m-1]可以解决的最大楼层数,第1层到第i - 1层是f[n-1][m-1]可以解决的最大楼层数,由此得到递推关系f[n][m]= f[n][m-1]+f[n-1][m-1]+1,然后对f[n][m-1],f[n-1][m-1]再按照上述公式分解,直到得出刚才所列的三种可计算情况(n = 1,或者m <= n)为止,再进行回溯累加,就可以得到f[n][m]的值

【Code】

#include<cstdio>
int f[1010][110];
int main()
{
    for (int i=1;i<=1000;i++)
        for (int j=1;j<=100;j++)
            f[i][j]=f[i][j-1]+f[i-1][j-1]+1;
    int T,n,m;
    scanf("%d",&T);
    for (int Case=1;Case<=T;Case++)
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
        if (f[n][i]>=m)
        {
            printf("Case %d: %d\n",Case,i);
            break;
        }
    }
}

I - Farm

【题意】
求矩形与圆相交的面积。已知矩形长宽>圆的半径,矩形左上角在圆中。
【思路】
将矩形和圆的公共部分分割成 两个部分, 一个三角形,和一个弓形( 弦与弧围成的区域 )区域。分别求面积即可。
【Code】

#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    double Xc,Yc,R,X1,Y1,X2,Y2,Xs,Ys,Xt,Yt,tmp,h,S1,S2,dist,alfa;
    for (int Case=1;Case<=T;Case++)
    {
        scanf("%lf %lf %lf",&Xc,&Yc,&R);
        scanf("%lf %lf %lf %lf",&Xs,&Ys,&Xt,&Yt);
        Xs-=Xc;Ys-=Yc;
        Xt-=Xc;Yt-=Yc;
        X1=Xs;
        Y1=-sqrt(R*R-X1*X1);
        Y2=Yt;
        X2=sqrt(R*R-Y2*Y2);
        dist=sqrt((X1-X2)*(X1-X2)+(Y1-Y2)*(Y1-Y2));
        S1=0.5*fabs((Y2-Y1)*(X1-X2));
        alfa=acos((R*R*2.0-dist*dist)/(2.0*R*R));
        S2=(R*R*0.5)*(alfa-sin(alfa));
        printf("Case %d: %.5f\n",Case,S1+S2);
    }
}

J - Weird Maze

【题意】
还没有看,日后更
【思路】
【Code】

这里写代码片
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值