Codeforces Round #259 (Div. 2) A/B/C/D

Little Pony and Crystal Mine


题意:给一个奇数n,打印菱形图案,整个图形占n*n格。

例如--->输入3,则打印图案如下

*D*
DDD
*D*


算法:

由中间那行为n个D,以t = n/2为界先打上半边,每一行由D隔开的*的个数为离中间行的距离。

D的个数为n-当前行离中间行的距离*2。

下半边同理。


#include<cstdio>
#include<iostream>
#include<cstring>

using namespace std;

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int h = n/2;
        for(int i=1;i<=h;i++)
        {
            for(int j=0;j<h+1-i;j++)
                putchar('*');
            for(int k=0;k<n-(h+1-i)*2;k++)
                putchar('D');
            for(int j=0;j<h+1-i;j++)
                putchar('*');
            puts("");
        }
        for(int i=h+1;i<=n;i++)
        {
            for(int j=0;j< i-h-1;j++)
                putchar('*');
            for(int k=0;k<n-(i-h-1)*2;k++)
                putchar('D');
            for(int j=0;j< i-h-1;j++)
                putchar('*');
            puts("");
        }
    }
    return 0;
}

B. Little Pony and Sort by Shift

题意:给你一个n个数组成的序列,每次只能把最后一个数移动到最前面,问是否能通过若干次这种移动使得
序列变为非递减的序列,如果不能输出-1,否则输出至少需要几次这样的操作。

算法:
经观察能通过操作变为非递减的序列的特点是:只有一处两个相邻的数是递减的,以这两个数中间切断,两边的
序列都应该是递增的。
所以先找到这个突然递减的点,然后扫描后一段(因为前一段在找分界线时已经间接判断是递增的了)如果又出现
第二处突然递减的点,则输出-1。 否则输出后面一段的个数。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define maxn 100010

using namespace std;

int a[maxn];

int main()
{
    int n,flag,t;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        flag = 0,t = -1;
        for(int i=0;i<n-1;i++)
        {
            if(a[i+1]<a[i])
            {
                t = i;
                break;
            }
        }
        if(t==-1)
        {
            printf("0\n");
            continue;
        }
        for(int i=t+1;i<n-1;i++)
        {
            if(a[i+1]<a[i])
            {
                flag = 1;
                break;
            }
        }
        if(flag || a[0]<a[n-1])
        {
            printf("-1\n");
            continue;
        }
        else printf("%d\n",n-t-1);
    }
    return 0;
}


C. Little Pony and Expected Maximum

题意:投掷一个m面的骰子n次,问得到的最大数的期望。

算法:
最大数为i,则得到i的概率为  ( i/m)^n -  (i-1/m)^n  即用(i/m)^n减去最大数为i-1的概率。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define maxm 100010

using namespace std;

double p[maxm],ans[maxm];

int main()
{
    int m,n;
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        double res = 0;
        ans[0] = 0;
        for(int i=1;i<=m;i++)
        {
            ans[i] = pow((i*1.0)/m,n);
            p[i] = ans[i]-ans[i-1];
        }
        for(int i=1;i<=m;i++)
            res += p[i]*i;
        printf("%lf\n",res);
    }
    return 0;
}


D. Little Pony and Harmony Chest

题意:
给一个序列a,要构造一个序列b,使得sum(|bi-ai|)最小且任意两个bi的最大公共因子为1。

开始想到的是由于最大公共因子为1,所以b序列应该全为素数组成。每次找最邻近的素数。
但这样是不对的。如果同一个素数出现两次,则他们的最大公共因子是它们本身。

算法:
1、ai的最大值为30,最小值为1,所以不管怎样 bi取1是能满足最大公共因子为1的限制的,
现在要寻找比取1使sum( |bi-ai|)更小的解。那么bi最大不会 超过59 (30-1 = 29 ,30+29 = 59) 。

2、由于任何一个数都能由若干个素数因子表示而成。要想最大的公共因子为1,则素数因子的
状态不能重复取。而60以内的素数只有17个,这时我们状态压缩,用每一位来表示第几个素数
因子。把1-59的素数因子用状态记录下来。

3、dp[i][j]表示前i个数得到j状态的最小的sum(|bi-ai|)值。

当前一个状态dp[i-1][k]的k&val[x]=0时,dp[i][k] = max(dp[i][k],dp[i-1][k^val[x]]+abs(a[i]-x)),val[x]表示
x的素数因子状态。

用ans[i][j]记录状态的转移,这样就好输出b序列。这里利用了^运算的可逆性。

#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 60
#define INF 0x3f3f3f3f
#include<cmath>

using namespace std;

bool isp[maxn];
int pri[maxn],c,a[110],b[110],val[maxn],dp[110][(1<<18)],ans[110][(1<<18)];

void init()
{
    memset(isp,0,sizeof(isp));
    c = 0;
    for(int i=2;i<maxn;i++)
    {
        if(!isp[i])
        {
            pri[c++] = i;
            for(int j=i*2;j<maxn;j+=i)
                isp[j] = true;
        }
    }
}

int main()
{
    int n;
    init();
    while(scanf("%d",&n)!=EOF)
    {
        memset(val,0,sizeof(val));
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<60;i++)
        {
            for(int j=0;j<c;j++)
            {
                if(i%pri[j]==0)
                    val[i] = (val[i]|(1<<j));
            }
        }
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<(1<<c);j++)
                dp[i][j] = INF;
        }
        for(int i=0;i<(1<<c);i++)
            dp[0][i] = 0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<(1<<c);j++)
            {
                for(int k=1;k<60;k++)
                {
                    if((j&val[k])==0)
                    {
                        int tmp = dp[i-1][j^val[k]]+fabs(a[i]-k);
                        if(tmp<dp[i][j])
                        {
                            dp[i][j] = tmp;
                            ans[i][j] = k;
                        }
                    }
                }
            }
        }
        int res = INF,state,x=0;
        for(int i=0;i<(1<<c);i++)
        {
            if(dp[n][i]<res)
            {
                res = dp[n][i];
                state = i;
            }
        }
        for(int i=n;i>=1;i--)
        {
            b[x++] = ans[i][state];
            int t = ans[i][state];
            state = state^val[t];
        }
        for(int i=x-1;i>0;i--)
            printf("%d ",b[i]);
        printf("%d\n",b[0]);
    }
    return 0;
}









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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值