A - Adrien and Austin(签到,博弈)
题目链接:2018南京 A - Adrien and Austin
题意:
两个人博弈,有n个石子,最多可以取连续的 m个,最终无法拿到石子的人就输,问谁会赢
解题思路:
当石子为0个时,第一个人没法拿,所以第二个人赢
当最多只能1个时,就分奇偶性,奇数第一个人赢,偶数第二个人赢
否则第一个人赢,因为第一个人先拿,可以将所有石子从中间拿掉一些,将剩下的等分为左右两部分,第二个人怎么拿,第一个人就怎么拿,这样第一个人肯定先没法拿。
举例: n = 10 m = 3;
初始:1 2 3 4 5 6 7 8 9 10
第一个人: 1 2 3 4 7 8 9 10 拿掉两个分别是 5, 6
这样左右两边完全相等,无论左边那几个,右边就拿几个
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, m;
while(cin >> n >> m){
if(n == 0){
cout << "Austin" << endl;
}
else if(m == 1){
if(n % 2 == 0){
cout << "Austin" << endl;
}
else{
cout << "Adrien" << endl;
}
}
else{
cout << "Adrien" << endl;
}
}
return 0;
}
J-Prime Game(思维,算贡献)
题意:
有一个长度为 n 的序列 a ,定义 mul(l, r) 为区间 [l, r] 中 a[i] 的乘积, fac(l, r) 为 mul(l, r) 不同素数因子的个数。求所有区间 fac 的和。
解题思路:
每个素数的贡献为 (i - vis[a[i]]) * (n - i + 1)。其中 i 表示第 i 个数(下标从1开始),vis[a[i]] 表示 a[i] 上一次出现的位置。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+3;
int prime[maxn], is_prime[maxn], cnt = 1;
ll vis[maxn]; // 此处虽然记下标
void solve(){
for(int i = 1; i < maxn; i++){
is_prime[i] = 1;
}
is_prime[2] = 1;
for(ll i = 2; i < maxn; i++){ // i 开 long long
if(is_prime[i] == 1){
prime[cnt] = i;
cnt++;
for(ll j = i * i; j < maxn; j = j + i){
is_prime[j] = 0;
}
}
}
}
int main(){
int n;
scanf("%d", &n);
solve();
ll ans = 0, a;
for(int i = 1; i <= n; i++){
cin >> a;
if(a == 1){
continue;
}
if(is_prime[a] == 0){
for(int j = 1; j < cnt; j++){
if(a == 1 || prime[j] * prime[j] > a){
break;
}
if(a % prime[j] == 0){
ans = ans + (n - i + 1) * (i - vis[prime[j]]);
vis[prime[j]] = i;
while(a % prime[j] == 0){
a = a / prime[j];
}
}
}
}
if(a > 1){ // a 本身是素数
ans = ans + (n - i + 1) * (i - vis[a]);
vis[a] = i;
}
}
printf("%lld\n", ans);
return 0;
}