首页 > 代码库 > Codeforces Round #259 (Div. 2) A/B/C/D
Codeforces Round #259 (Div. 2) A/B/C/D
A 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; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。