您的位置:首页 > 其它

洛谷 2158 数论 打表 欧拉函数

2016-11-08 11:21 267 查看

洛谷 2158 数论 递推 欧拉函数 打表找规律

传送门 (https://www.luogu.org/problem/show?pid=2158#sub)

其实看到SDOI就有一种不太好的预感,,想当年那个猪国杀,,,呵呵,,

20分暴力

用二维数组维护每个点能否被选择,之后二维枚举每个点,如果没有被选择就选择,并且用它去遮挡其他所有点

#include <cstdio>
#include <cstring>
#include <algorithm>

const int maxn = 1000 + 10;

int a[maxn][maxn];
int n;
int sum;
// int ansx[maxn];
// int ansy[maxn];

void update (int x, int y) {
int curx = x, cury = y;
while (curx <= n && cury <= n) {
curx += (x - 1);
cury += (y - 1);
a[curx][cury] = 1;
}
}

int main () {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
a[1][i] = 1;
a[i][1] = 1;
}
sum = 2;
// ansx[1] = 1;
// ansy[1] = 2;
// ansx[2] = 2;
// ansy[2] = 1;
for (int i = 2; i <= n; i++) {
for (int j = 2; j <= n; j++) {
if (a[i][j] == 0) {
a[i][j] = 1;
sum++;
// ansx[sum] = i;
// ansy[sum] = j;
update(i, j);
}
}
}
printf("%d\n", sum);
//for (int i = 1; i <= sum; i++) {
//     printf("x : %d  y : %d\n", ansx[i], ansy[i]);
// }

return 0;
}

正解:

其实这道题的正解是打表打出来的,大概把数字取到10左右就能发现某种性质,

x : 1  y : 2
x : 2  y : 1
x : 2  y : 2
x : 2  y : 3
x : 2  y : 4
x : 2  y : 5
x : 2  y : 6
x : 2  y : 7
x : 2  y : 8
x : 2  y : 9
x : 2  y : 10
x : 3  y : 2
x : 3  y : 4
x : 3  y : 6
x : 3  y : 8
x : 3  y : 10
x : 4  y : 2
x : 4  y : 3
x : 4  y : 5
x : 4  y : 6
x : 4  y : 8
x : 4  y : 9
x : 5  y : 2
x : 5  y : 4
x : 5  y : 6
x : 5  y : 8
x : 5  y : 10
x : 6  y : 2
x : 6  y : 3
x : 6  y : 4
x : 6  y : 5
x : 6  y : 7
x : 6  y : 8
x : 6  y : 9
x : 6  y : 10
x : 7  y : 2
x : 7  y : 6
x : 7  y : 8
x : 8  y : 2
x : 8  y : 3
x : 8  y : 4
x : 8  y : 5
x : 8  y : 6
x : 8  y : 7
x : 8  y : 9
x : 8  y : 10
x : 9  y : 2
x : 9  y : 4
x : 9  y : 6
x : 9  y : 8
x : 9  y : 10
x : 10  y : 2
x : 10  y : 3
x : 10  y : 5
x : 10  y : 6
x : 10  y : 8
x : 10  y : 9

由此可见,每个点可取的值与phi[i-1]有关,故使用筛法线性求欧拉函数,之后根据对称性并考虑特殊点,将ans = ans * 2 + 1即为结果

#include <cstdio>
#include <algorithm>
#include <cstring>

const int maxn = 40000 + 100;

int phi[maxn], isprime[maxn], prime[maxn];
int n;
int tot = 0;
long long ans = 0;

int main () {
scanf("%d", &n);
phi[1] = 1;
for (int i = 1; i <= n; i++) isprime[i] = 1;
for (int i = 2; i <= n; i++) {
if (isprime[i]) {
tot++;
prime[tot] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= tot; j++) {
if (i * prime[j] > n) break;
isprime[i * prime[j]] = 0;
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
} else {
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
// for (int i = 1; i <= n; i++) printf("phi[%d] = %d\n", i, phi[i]);
for (int i = 2; i <= n; i++) {
ans = ans + (long long)phi[i-1];
}
ans = ans * 2 + 1;
printf("%lld", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: