C. Pride

传送门:http://codeforces.com/contest/892/problem/C

本题是一个关于序列的数学问题——最大公约数(GCD)。

对于一个长度为n的序列A={a[i]|i=1,2,...,n},有以下操作:选定序列中的两个相邻元素,记为xy,将其中一个替换成gcd(x,y)。这个序列是否可以在有限步操作后,变成一个所有元素均为1的序列?若可行,则求最小操作步数;否则返回-1。

首先考虑可行性:若gcd{a[i]|i=1,2,...,n}=1,则可行;否则不可行。

之后,考虑每一个元素的情况:记cnt=card{i|a[i]=1},则当cnt>0时,ans=n-cnt

之后,考虑每一段区间l~r(l<r)上的情况:记g(l,r)=gcd{a[i]|i=l,...,r},则有以下递推关系式:g(l,r+1)=gcd(g(l,r),a[r+1])。若存在l<r,使得g(l,r)=1,令d=r-l,则有操作步数step=n+d-1。

注意这个操作步数的计算。在当前情况下,首先在区间l~r上构造出一个元素1:d步;再用这个1与其他元素作GCD运算:n-1步。于是总操作步数为step=n+d-1。

于是,枚举lr,求最小的d=r-l即可。时间复杂度为O(n2)。参考程序如下:

#include <stdio.h>
#include <stdlib.h>
#define MAX_N 2000
#define INF 0xffff int a[MAX_N]; int gcd(int x, int y)
{
if (y == ) return x;
return gcd(y, x % y);
} int main(void)
{
int n;
scanf("%d", &n);
int cnt = ;
for (int i = ; i < n; i++) {
scanf("%d", &a[i]);
if (a[i] == ) cnt++;
}
if (cnt) {
printf("%d\n", n - cnt);
exit();
}
int d = INF;
for (int i = ; i < n; i++) {
int g = a[i];
for (int j = i + ; j < n; j++) {
g = gcd(g, a[j]);
if (g == && j - i < d) d = j - i;
}
}
if (d != INF) printf("%d\n", n + d - );
else printf("-1\n");
return ;
}

D. Gluttony

传送门:http://codeforces.com/contest/892/problem/D

本题是一个关于序列的数学问题——重排问题。

给定由n个不同元素组成的序列A={a[i]|i=1,2,...,n},试将其重排为序列B={b[i]|i=1,2,...,n},使得对于任意一个{1,2,...,n}的非空真子集S,有$\sum_{i\in S}a[i] \neq\sum_{i\in S}b[i]$。

首先考虑一个特殊的情形:序列A是上升的。此时,只要将A循环左移一位,即得到满足条件的序列B。这个序列B的通项为b[i]=a[i%n+1],i=1,2,...,n。下证之:

由于序列B由序列A重排而来,因此$\sum_{i=1}^{n}a[i] =\sum_{i=1}^{n}b[i]$,记这个和为X

对于i=1,2,...,n-1,有b[i]=a[i+1]>a[i];此外,有b[n]=a[1]<a[n]。

于是,①若n不是集合S中的元素,则显然有$\sum_{i\in S}a[i] <\sum_{i\in S}b[i]$;

②若n是集合S中的元素,则记集合T={1,2,...,n}-S,则n不是集合T中的元素,因此有$\sum_{i\in T}a[i] <\sum_{i\in T}b[i]$。于是,$\sum_{i\in S}a[i] =X-\sum_{i\in T}a[i] >X-\sum_{i\in T}b[i] =\sum_{i\in S}b[i]$。

综上所述,对于任意一个{1,2,...,n}的非空真子集S,有$\sum_{i\in S}a[i] \neq\sum_{i\in S}b[i]$。

循环移位操作是{1,2,...,n}上的一个变换,记为G:g(i)=i%n+1。

于是,对于一个有序的A,进行简单的循环移位操作。而对于一个无序的A,则考虑先排序。

f(i)表示序列A中第i小的元素在A中的位置,即A中第i小的元素为a[f(i)]。于是,可将F:f(i)看作{1,2,...,n}上的一个变换。变换F可以通过排序构造,时间复杂度为O(nlogn)~O(n2)。

如此,设序列C={a[f(i)]|i=1,2,...,n},则C是一个上升序列,通项为c[i]=a[f(i)],i=1,2,...,n。于是,可以对C进行循环移位,生成序列D。则D的通项为d[i]=c[i%n+1]=a[f(i%n+1)]。

由于C=F(A),D=G(C),故所求序列B满足D=F(B)。由式D=F(B),有b[f(i)]=d[i]=a[f(i%n+1)]。

参考程序如下:

#include <stdio.h>
#define MAX_N 22 int a[MAX_N], b[MAX_N], f[MAX_N]; int main(void)
{
int n;
scanf("%d", &n);
for (int i = ; i < n; i++) {
scanf("%d", &a[i]);
f[i] = i;
}
for (int i = ; i < n; i++) {
for (int j = ; j < i; j++) {
if (a[f[i]] < a[f[j]]) {
int t = f[i];
f[i] = f[j];
f[j] = t;
}
}
}
for (int i = ; i < n; i++)
b[f[i]] = a[f[(i + ) % n]];
for (int i = ; i < n; i++)
printf("%d ", b[i]);
return ;
}

最新文章

  1. jquery时间日期三级联动
  2. 前端学PHP之面向对象系列第四篇——关键字
  3. [css]当父元素的margin-top碰上子元素的margin-top
  4. nginx 在windows平台上对asp.net做反向代理
  5. 20145320《Java程序设计》第一次实验报告
  6. Java多线程之新类库中的构件PriorityBlockingQueue
  7. [CCPC2016]网赛部分比赛代码
  8. PHP 截取字符串专题
  9. 动态创建二维vector数组 C和C++ 及指针与引用的区别
  10. ubuntu 13.10 64bit装BeyondCompare
  11. 偶遇mysql外键不好使
  12. SqlLite ---.net连接数据库
  13. path sum i
  14. JS Event事件流(冒泡机制、捕获机制、事件绑定)
  15. 14_Python字符串操作方法总结
  16. CSRF篇-本着就了解安全本质的想法,尽可能的用通俗易懂的语言去解释安全漏洞问题
  17. 50个常用的Linux命令(二)sed
  18. centos7 yum install timeout
  19. centos7,php7 安装mysqli扩展
  20. sql中替换换行符和空格的示例

热门文章

  1. 【Git使用具体解释】Egit使用过程中遇到的问题及解决的方法
  2. 高阶MapReduce_1_链接多个MapReduce作业
  3. Android EditText得到和失去焦点时,自定义处理内容
  4. PCB Genesis加邮票孔(邮票孔增加方向判断--左右上下)实现算法
  5. NOIP 2015 DAY2
  6. Python 40 数据库-约束
  7. 混个脸熟 -- go
  8. POJ 2945 trie树
  9. (List)写一个函数reverseList,该函数能够接受一个List,然后把该List&#160;倒序排列。&#160;例如:&#160; List&#160;list&#160;=&#160;new&#160;ArrayList();&#160; list.add(“Hello”);&#160; list.add(“World”);&#160; list.add(“Learn”);&#160;//此时list&#160;为Hello&#160;World&#160;Learn&#160; rever
  10. Java:Java 队列的遍历