http://codeforces.com/contest/1312
A. Two Regular Polygons
http://codeforces.com/contest/1312/problem/A
题目大意:
对于正 n n n边形 A A A,是否存在正 m m m边形 B B B,满足:
- B B B的中心与 A A A的中心重合
- B B B的顶点都在 A A A的顶点上
第一行输入一个正整数 t t t ( 1 ≤ t ≤ 1 0 4 ) (1≤t≤10^4) (1≤t≤104),表示有 t t t 组输入,之后 t t t 行代表 t t t 组输入,每组输入一行两个空格分隔的正整数 n n n 和 m m m ( 3 ≤ m < n ≤ 100 ) (3≤m<n≤100) (3≤m<n≤100),判断是否存在满足条件的多边形,存在输出"YES",否则输出"NO",一行一个输出。
结论:
当
n
n
n能被
m
m
m整除时,满足条件。
简单证明:
作
A
A
A的外接圆,
A
A
A的每条边所对圆心角相等,设其大小为
α
\alpha
α。将
B
B
B的中心与
A
A
A的中心的重合,显然这个圆也是
B
B
B的外接圆,设B的每条边所对圆心角大小为
β
\beta
β。当
B
B
B的顶点在
A
A
A的顶点上时,显然有
β
=
k
α
\beta=k\alpha
β=kα(
k
k
k为正整数)。又因为
n
α
=
m
β
n\alpha=m\beta
nα=mβ,所以
n
=
k
m
n=km
n=km,即
n
n
n能被
m
m
m整除。
代码:
#include <cstdio>
using namespace std;
int main() {
int t, m, n;
while(~scanf("%d", &t)) {
while(t--) {
scanf("%d%d", &n, &m);
printf(n % m ? "NO\n" : "YES\n");
}
}
return 0;
}
B. Bogosort
http://codeforces.com/contest/1312/problem/B
题目大意:
给定数列
a
1
,
a
2
,
⋯
,
a
n
a_1,a_2,\cdots,a_n
a1,a2,⋯,an,对于任意的下标
i
,
j
(
i
<
j
)
i,j(i<j)
i,j(i<j) 满足
j
−
a
j
≠
i
−
a
i
j−a_j≠i−a_i
j−aj=i−ai ,则称这个数列是“好的”,现在给你一个数列
a
a
a,重新排列元素的顺序,将这个数列
a
a
a变成“好的”。
第一行输入一个正整数 t t t ( 1 ≤ t ≤ 100 ) (1≤t≤100) (1≤t≤100),表示有 t t t 组输入,之后 2 t 2t 2t 行代表 t t t 组输入,每组输入第一行一个正整数 n ( 1 ≤ n ≤ 100 ) n (1≤n≤100) n(1≤n≤100)表示数列 a a a 的长度,第二行输入 n n n 个正整数 a 1 , a 2 , ⋯ , a n ( 1 ≤ a i ≤ 100 ) a_1,a_2,\cdots,a_n(1≤ai≤100) a1,a2,⋯,an(1≤ai≤100)。
输出一行重新排序后的数列。
思路:
将
j
−
a
j
≠
i
−
a
i
j−a_j≠i−a_i
j−aj=i−ai 改变一下形式,得到
i
−
j
≠
a
i
−
a
j
i−j≠a_i-a_j
i−j=ai−aj ,因为
i
<
j
i<j
i<j ,只要满足
a
i
−
a
j
≥
0
a_i-a_j ≥ 0
ai−aj≥0,即
a
i
≥
a
j
a_i≥ a_j
ai≥aj 不等式一定成立,所以将数组降序排列就一定是“好的”。
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int t, n, a[105];
while(~scanf("%d", &t)) {
while(t--) {
scanf("%d", &n);
for(register int i = 0; i < n; ++i)
scanf("%d", a + i);
sort(a, a + n, greater<int>());
for(register int i = 0; i < n; ++i)
printf(i == n - 1 ? "%d\n" : "%d ", *(a + i));
}
}
return 0;
}
C. Adding Powers
http://codeforces.com/contest/1312/problem/C
题目大意:
对一初始各项均为
0
0
0 的数列
v
1
,
v
2
,
⋯
,
v
n
v_1,v_2,\cdots,v_n
v1,v2,⋯,vn,有如下算法:
在第
i
i
i(
i
i
i 从
0
0
0 开始)次操作,可以进行以下两种操作的其中一种:
- 选择一个位置 p o s ( 1 ≤ p o s ≤ n ) pos (1≤pos≤n) pos(1≤pos≤n),给 v p o s v_{pos} vpos 加上 k i k^i ki;
- 不选择任何位置并跳过这步。
你可以决定算法怎么进行以及何时停止,现给出一个数列 a a a ,能否在若干次操作后使 v v v 等于 a a a (即数列中每个元素对应相等)。
第一行输入一个正整数 T T T ( 1 ≤ T ≤ 1000 ) (1≤T≤1000) (1≤T≤1000),表示有 T T T 组输入,之后有 2 T 2T 2T 行,每 2 2 2 行为 1 1 1 组输入,每组输入第一行两个正整数 n n n 和 k ( 1 ≤ n ≤ 30 , 2 ≤ k ≤ 100 ) k (1≤n≤30, 2≤k≤100) k(1≤n≤30,2≤k≤100) ,第二行 n n n 个正整数 a 1 , a 2 , ⋯ , a n ( 0 ≤ a i ≤ 1 0 16 ) a_1,a_2,\cdots,a_n (0≤ai≤10^{16}) a1,a2,⋯,an(0≤ai≤1016)。
一行一个输出,如果 v v v 经过变换后能够变为 a a a,输出"YES",否则输出"NO"。
思路:
要使
v
v
v 能够变为
a
a
a ,
a
a
a 中的每一项一定是
k
k
k的若干次幂的和。
联想到进制转换中位权的概念。比如将 ( 3 A ) 16 (3A)_{16} (3A)16转化为十进制,进行的计算为 10 × 1 6 0 + 3 × 1 6 1 10\times16^0 + 3 \times16^1 10×160+3×161 得到十进制数 58 58 58。而对于题目中的操作, k k k 的 i i i 次幂就相当于位权,因此将 a a a 中的数都转化为 k k k 进制。
由于 i i i 是不会重复的,开一个数组 c n t cnt cnt 记录各个指数出现的次数,大于 1 1 1 说明 v v v 无法变为 a a a。此外, k i k^i ki 前的系数为 1 1 1,所以 k k k 进制数中应当只含有 0 0 0 或 1 1 1,否则 v v v 也无法变为 a a a。注意 a a a 的范围, l o g 2 1 0 16 log_210^{16} log21016 约为 53.15 53.15 53.15,因此保险起见数组 c n t cnt cnt 开到60。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int t, n, k, cnt[60];
ll a[31];
inline bool judge(ll a[], int k) {
for(register int i = 0; i < n; ++i) {
for(register int j = 0; a[i]; ++j) {
int r = a[i] % k;
if(r == 1)
++cnt[j];
else if(r > 1)
return false;
a[i] /= k;
}
}
for(register int i = 0; i < 60; ++i) {
if(cnt[i] > 1)
return false;
}
return true;
}
int main() {
while(~scanf("%d", &t)) {
while(t--) {
scanf("%d %d", &n, &k);
for(register int i = 0; i < n; ++i)
scanf("%lld", a + i);
memset(cnt, 0, sizeof(cnt));
printf(judge(a, k) ? "YES\n" : "NO\n");
}
}
return 0;
}