A 串

题目描述

长度不超过 ,且包含子序列“us”的、只由小写字母构成的字符串有多少个? 答案对 取模。
所谓子序列,指一个字符串删除部分字符(也可以不删)得到的字符串。
例如,"unoacscc"包含子序列"us",但"scscucu"则不包含子序列"us"

输入描述:

一个正整数

输出描述:

一个正整数,为满足条件的字符串数量对 取模的值

分析:

表示长度为 且不包含 'u','s' 这两个字符的字符串个数.

表示长度为 且不包含 'u' 这个字符的字符串个数.

表示长度为 且不包含 's' 这个字符的字符串个数.

表示长度为 且不包含子序列 "us" 且包含子序列 "us"的字符串个数.

有状态转移方程

f[i][0] = f[i - 1][0] * 24;
f[i][1] = f[i - 1][0] + f[i - 1][1] * 25;
f[i][2] = f[i - 1][0] + f[i - 1][2] * 25;
f[i][3] = f[i - 1][3] * 25 + f[i - 1][2];

因此包含子序列 "us" 的字符串个数为 .

代码实现:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const int M = (int)1e6;
const int N = (int)2e4;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const ll mod = (ll)1e9 + 7;

ll f[M + 5][4];

ll quick(ll a, ll b, ll p = mod)
{
    a %= p;
    ll s = 1;
    while(b)
    {
        if(b & 1) s = s * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return s % p;
}

ll inv(ll n, ll p = mod)
{
    return quick(n, p - 2, p);
}

void work()
{
    int n; scanf("%d", &n);
    f[0][0] = 1;
    for(int i = 1; i <= n; ++i)
    {
        f[i][0] = f[i - 1][0] * 24 % mod;
        f[i][1] = (f[i - 1][0] + f[i - 1][1] * 25) % mod;
        f[i][2] = (f[i - 1][0] + f[i - 1][2] * 25) % mod;
        f[i][3] = (f[i - 1][3] * 25 + f[i - 1][2]) % mod;
    }
    ll s = 0;
    for(int i = 2; i <= n; ++i)
        s = (s + f[i][0] + f[i][1] + f[i][2] + f[i][3]) % mod;
    s = 26 * 26 % mod * (quick(26, n - 1) - 1) % mod * inv(25) % mod - s;
    s = (s % mod + mod) % mod;
    printf("%lld\n", s);
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
//    int T; scanf("%d", &T);
//    while(T--) work();
    work();
//    cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
    return 0;
}

B 括号

题目描述

请你构造一个非空的括号字符串,包含正好 个不同合法括号对。
所谓括号字符串,是指由'('和')'这两种字符构成的字符串。
要求构造的字符串长度不超过

输入描述:

一个整数

输出描述:

一个仅包含左右括号字符串,其中有 个合法的括号对。如果有多种构造方法,输出任意一种合法方案即可。

分析:

比赛时没找到好康的构造策略,于是开始瞎搞...

代码实现:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const int M = (int)1e8;
const int N = (int)2e4;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const ll mod = (ll)1e9 + 7;

stack<char> st;

void work()
{
    int k; scanf("%d", &k);
    if(k == 0) {printf(")\n"); return;}
    int n = 1; while(1ll * n * n <= k) ++n;
    --n;
    int s = n * n;
    for(int i = 1; i <= n; ++i) st.emplace(')');
    for(int i = n; i >= 1; --i)
    {
        if(s + i <= k) st.push(')'), s += i;
        st.push('(');
    }
    st.pop();
    while(s < k)
    {
        st.push(')');
        ++s;
    }
    st.push('(');
    while(!st.empty())
    {
        printf("%c", st.top());
        st.pop();
    }
    printf("\n");
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
//    int T; scanf("%d", &T);
//    while(T--) work();
    work();
//    cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
    return 0;
}

C 红和蓝

题目描述

你拿到了一棵树,请你给每个顶点染成红色或蓝色。
要求:每个红点周围有且仅有一个红点,每个蓝点周围有且仅有一个蓝点。
“周围”的定义:某点周围的点指通过邻边直接连接的点。
所谓树,即没有自环、重边和回路的无向连通图。

输入描述:

第一行一个正整数 ,代表树的顶点个数。
接下来的 行,每行两个正整数 ,代表点 和点 有一条边连接。
保证输入的一定是一棵合法的树。

输出描述:

如果可以达成染色的要求,请输出一个长度为 的字符串,第 个字符代表第 个顶点的染色情况,'B' 代表蓝色,'R' 代表红色。(若有多种合法染色的方法,输出任意一种即可)
否则直接输出-1。

分析:

表示在以 为根的子树中, 号点的颜色为 是否能构造出合法方案.

然后胡乱写写就过了

Q:小姐姐你的代码好长啊?!
A:没错,我的就是很长!(?

代码实现:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const int M = (int)1e5;
const int N = (int)2e4;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const ll mod = (ll)1e9 + 7;

int n, cnt;
int head[M + 5];
struct enode
{
    int v, nx;
}Edge[M * 2 + 5];

void init()
{
    cnt = 0;
    for(int i = 1; i <= n; ++i)
    {
        head[i] = -1;
    }
}

void add(int u, int v)
{
    Edge[cnt].v = v;
    Edge[cnt].nx = head[u];
    head[u] = cnt++;
}

int f[M + 5][2];
int sz[M + 5];

void dfs(int u, int fa)
{
    sz[u] = 1;
    f[u][0] = 0, f[u][1] = 0;
    for(int i = head[u]; ~i; i = Edge[i].nx)
    {
        int v = Edge[i].v;
        if(v == fa) continue;
        dfs(v, u);
        sz[u] += sz[v];
    }
    if(sz[u] & 1)
    {
        int son = -1;
        for(int i = head[u]; ~i; i = Edge[i].nx)
        {
            int v = Edge[i].v;
            if(v == fa) continue;
            if(sz[v] & 1) son = v;
        }
        if(son == -1)
        {
            bool flag = 1;
            for(int i = head[u]; ~i; i = Edge[i].nx)
            {
                int v = Edge[i].v;
                if(v == fa) continue;
                if(f[v][0] == 0) flag = 0;
            }
            if(flag) f[u][1] = 1;

            flag = 1;
            for(int i = head[u]; ~i; i = Edge[i].nx)
            {
                int v = Edge[i].v;
                if(v == fa) continue;
                if(f[v][1] == 0) flag = 0;
            }
            if(flag) f[u][0] = 1;
        }
    }
    else
    {
        int son = -1;
        for(int i = head[u]; ~i; i = Edge[i].nx)
        {
            int v = Edge[i].v;
            if(v == fa) continue;
            if(sz[v] & 1)
            {
                if(son == -1) son = v;
                else          {son = -1; break;}
            }
        }
        if(son != -1)
        {
            bool flag = 1;
            for(int i = head[u]; ~i; i = Edge[i].nx)
            {
                int v = Edge[i].v;
                if(v == fa) continue;
                if(v == son) continue;
                if(f[v][1] == 0) flag = 0;
            }
            if(flag) f[u][0] = f[son][0];

            flag = 1;
            for(int i = head[u]; ~i; i = Edge[i].nx)
            {
                int v = Edge[i].v;
                if(v == fa) continue;
                if(v == son) continue;
                if(f[v][0] == 0) flag = 0;
            }
            if(flag) f[u][1] = f[son][1];
        }
    }
//    printf("f[%d][0] = %d\n", u, f[u][0]);
//    printf("f[%d][1] = %d\n", u, f[u][1]);
}

char s[M + 5];

void dfs2(int u, int fa)
{
    for(int i = head[u]; ~i; i = Edge[i].nx)
    {
        int v = Edge[i].v;
        if(v == fa) continue;
        if(sz[v] & 1)
        {
            s[v] = s[u];
        }
        else
        {
            if(s[u] == 'R') s[v] = 'B';
            else if(s[u] == 'B') s[v] = 'R';
        }
        dfs2(v, u);
    }
}

void work()
{
    scanf("%d", &n); init();
    for(int i = 1, a, b; i <= n - 1; ++i)
    {
        scanf("%d %d", &a, &b);
        add(a, b), add(b, a);
    }
    dfs(1, 0);
    if(sz[1] & 1) {printf("-1\n"); return;}
    if(f[1][0])
    {
        s[1] = 'R';
        dfs2(1, 0);
        s[n + 1] = '\0';
        printf("%s\n", s + 1);
    }
    else if(f[1][1])
    {
        s[1] = 'B';
        dfs2(1, 0);
        s[n + 1] = '\0';
        printf("%s\n", s + 1);
    }
    else    printf("-1\n");
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
//    int T; scanf("%d", &T);
//    while(T--) work();
    work();
//    cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
    return 0;
}

D 点一成零

题目描述

牛牛拿到了一个n*n的方阵,每个格子上面有一个数字:0或1
行和列的编号都是从0到n-1
现在牛牛每次操作可以点击一个写着1的格子,将这个格子所在的1连通块全部变成0。
牛牛想知道,自己有多少种不同的方案,可以把全部格子的1都变成0?
所谓连通块,是指方阵中的两个正方形共用一条边,即(x,y)和以下4个坐标的数是连通的:(x-1,y)、(x+1,y)、(x,y-1)、(x,y+1)
这个问题对于牛牛来说可能太简单了。于是他将这个问题变得更加复杂:
他会选择一个格子,将这个格子上的数字修改成1(如果本来就是1,那么不进行任何改变),再去考虑“点一成零”的方案数。
牛牛想知道,每次“将某个格子修改成1”之后,“把全部格子的1都变成0”的方案数量。
ps:请注意,每次“将某个格子修改成1”之后,状态会保留到接下来的询问。具体请参考样例描述。
由于方案数可能过大,请对 取模

输入描述:

第一行输入一个 n(
随后 行每行有一个 长度为 的字符串,字符串只可能包含 '0' 或 '1' 字符 ,表示整个方阵
接下来输入一个数 ,表示询问的次数。(
随后 行每行有 2 个整数 表示将 列的数字变为 1 的一次修改操作

输出描述:

针对每一次变更数字的操作,输出当前的方案数

分析:

并查集维护,操作的时候顺便更新答案就行了.

代码实现:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const int M = (int)5e2;
const int N = (int)2e4;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const ll mod = (ll)1e9 + 7;

int n, k;
char s[M + 5][M + 5];
int sz[M * M + 5];
int fa[M * M + 5];
ll fac[M * M + 5];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};

int tofind(int x)
{
    if(x == fa[x]) return x;
    return fa[x] = tofind(fa[x]);
}

inline int id(int i, int j)
{
    return i * n + j;
}

ll quick(ll a, ll b, ll p = mod)
{
    a %= p;
    ll s = 1;
    while(b)
    {
        if(b & 1) s = s * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return s % p;
}

ll inv(ll n, ll p = mod)
{
    return quick(n, p - 2, p);
}

/**
5
00110
00111
00000
01001
10100
3
1 3
1 2
4 3

**/

void work()
{
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) scanf("%s", s[i]);
    for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) fa[id(i, j)] = id(i, j), sz[id(i, j)] = 1;
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < n; ++j)
        {
            if(s[i][j] == '0') continue;
            for(int k = 0; k < 4; ++k)
            {
                int x = i + dx[k], y = j + dy[k];
                if(x < 0 || x >= n || y < 0 || y >= n || s[x][y] == '0') continue;
                int a = id(i, j), b = id(x, y);
                a = tofind(a), b = tofind(b);
                if(a != b)
                {
                    fa[a] = b;
                    sz[b] += sz[a];
                }
            }
        }
    }
    ll ans = 1; int p = 0;
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < n; ++j)
        {
            if(s[i][j] == '0') continue;
            int a = id(i, j);
            if(a != fa[a]) continue;
            ans = ans * sz[a] % mod * inv(fac[p]) % mod * fac[p + 1] % mod;
            ++p;
        }
    }
    int i, j, x, y;
    scanf("%d", &k);
    while(k--)
    {
        scanf("%d %d", &i, &j);
        if(s[i][j] == '0')
        {
            s[i][j] = '1';
            ans = ans * inv(fac[p]) % mod * fac[p + 1] % mod;
            ++p;
            for(int k = 0; k < 4; ++k)
            {
                int x = i + dx[k], y = j + dy[k];
                if(x < 0 || x >= n || y < 0 || y >= n || s[x][y] == '0') continue;
                int a = id(i, j), b = id(x, y);
                a = tofind(a), b = tofind(b);
                if(a != b)
                {
                    fa[a] = b;
                    ans = ans * inv(sz[a]) % mod
                              * inv(sz[b]) % mod
                              * (sz[a] + sz[b]) % mod
                              * inv(fac[p]) % mod
                              * fac[p - 1] % mod;
                    --p;
                    sz[b] += sz[a];
                }
            }
        }
        printf("%lld\n", ans);
    }
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
//    int T; scanf("%d", &T);
//    while(T--) work();
    fac[0] = 1;
    for(int i = 1; i <= M * M; ++i) fac[i] = fac[i - 1] * i % mod;
    work();
//    cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
    return 0;
}

E 三棱锥之刻

题目描述

牛牛站在一个棱长为的正三棱锥内部的中心。(牛牛是不可移动的)
(所谓正三棱锥,指六条棱都相等的三棱锥。正三棱锥的中心指到 4 个顶点距离都相等的那个点)
图片说明
如上图,,牛牛站在P点,
他拿着一个染色喷雾,可以用来给正三棱锥的内表面染色。
已知喷雾能喷洒的距离为。也就是说,三棱锥内表面距离牛牛不超过的点才有可能被染色。牛牛想知道,正三棱锥内表面能被他染色的最大面积是多少?
ps:牛牛可看成一个无大小的点。重力对于喷雾的影响忽略不计。

输入描述:

两个正整数和

输出描述:

染色的最大面积。若你的答案和正确答案误差不超过 ,则认为你的答案正确。

分析:

分四种情况讨论再鸡个分就行了.

吐槽:
前天刚被卡了精度,今天又被卡了...
例如这段代码是 WA 的

double s = 0, lim = sqrt(r * r - 3.0 / 36.0 * a * a);
double th = acos(1.0 - 3.0 / 36.0 * a * a / r / r);

改成这个样子就 AC 了???

double s = 0, lim = sqrt(r * r - 3.0 / 36.0 * a * a);
double th = acos(lim / r);

原因就在于 WA 掉的代码中出现了大数减小数导致精度严重丢失的问题.

代码实现:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const int M = (int)1e6;
const int N = (int)2e4;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const ll mod = (ll)1e9 + 7;
const double PI = acos(-1.0);

void work(double a, double r)
{
    if(36 * r * r <= 3 * a * a)  {printf("%.12f\n", 4 * PI * r * r); return;}
    if(9 * r * r >= 3 * a * a)   {printf("%.12f\n", sqrt(3) * a * a); return;}
    double s = 0, lim = sqrt(r * r - 3.0 / 36.0 * a * a);
    double th = acos(lim / r);
    s += -sqrt(3.0) / 6 * a * lim;
    s += r * r / 2.0 * ((PI / 2.0) - (th - 0.5 * sin(2 * th)));
    double ans = 4 * (PI * r * r - 6.0 * s);
    printf("%.12f\n", ans);
}

void work()
{
    int a, r; scanf("%d %d", &a, &r);
    if(144 * r * r <= 6 * a * a) {printf("0\n"); return;}
    work(1.0 * a, sqrt(r * r - 6.0 / 144.0 * a * a));
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
//    int T; scanf("%d", &T);
//    while(T--) work();
    work();
//    cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
    return 0;
}

F 对答案一时爽

题目描述

考试结束了,牛牛和牛妹开始对答案。
每道题有 ABCD 四个选项,一共有道题,全部是单选题,每道题正确得 1 分,错误不得分。
牛牛和牛妹互相知道了他们每道题选择的选项。他们想知道,两个人得分之和有可能达到的最大值和最小值是多少?

输入描述:

第一行输入一个正整数(
第二行输入一行个字符('A'、'B'、'C'、'D'中的一种),用空格隔开。第个字符代表牛牛第题的选项。
第三行输入一行个字符('A'、'B'、'C'、'D'中的一种),用空格隔开。第个字符代表牛妹第题的选项。

输出描述:

牛牛和牛妹得分之和的能达到的最大值和最小值。用空格隔开。

分析:

签到题.

代码实现:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const int M = (int)1e5;
const int N = (int)2e4;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const ll mod = (ll)1e9 + 7;

int n;
char s[M + 5];
char t[M + 5];

int getMax()
{
    int ans = 0;
    for(int i = 1; i <= n; ++i)
    {
        if(s[i] == t[i]) ans += 2;
        if(s[i] != t[i]) ans += 1;
    }
    return ans;
}

int getMin()
{
    return 0;
}

void work()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
    {
        getchar();
        scanf("%c", &s[i]);
    }
    for(int i = 1; i <= n; ++i)
    {
        getchar();
        scanf("%c", &t[i]);
    }
    printf("%d %d\n", getMax(), getMin());
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
//    int T; scanf("%d", &T);
//    while(T--) work();
    work();
//    cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
    return 0;
}

G 好玩的数字游戏

好像是个恶心模拟题,以后在做吧(咕咕咕)

H 幂塔个位数的计算

求底数为,层数为的幂塔的个位数是多少?
定义为底,层的幂塔为
例如
图片说明
图片说明
用数学语言表示,
的个位数。

输入描述:

第一行输入一个正整数。
第二行输入一个正整数。

输出描述:

一个数字,代表幂塔的个位数

分析:

欧拉降幂经典题了.

代码实现:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const int M = (int)1e5;
const int N = (int)2e4;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const ll mod = (ll)1e9 + 7;

int a, n;
string sa, sn;

ll SMod(string sa, ll m)
{
    int n = sa.size(), rem = 0;
    for(int i = 0; i < n; ++i) rem = (rem * 10 + sa[i] - '0') % m;
    return rem;
}

ll Mod(ll n, ll p)
{
    return n < p ? n : n % p + p;
}

ll Mod(string sa, ll p)
{
    int lensa = sa.size();
    int rem = 0;
    if(lensa > 1) return SMod(sa, p) + p;
    else          return Mod(SMod(sa, 100), p);
}

ll quick(string sa, ll b, ll p = mod)
{
    int a = Mod(sa, p);
    ll s = 1;
    while(b)
    {
        if(b & 1) s = Mod(s * a, p);
        a = Mod(a * a, p);
        b >>= 1;
    }
    return s;
}

int phi[] = {0, 1, 2, 3, 2, 4, 2, 6, 4, 6, 4};

ll cal(int u, int m)
{
    if(u == n || m == 1) return Mod(sa, m);
    return quick(sa, cal(u + 1, phi[m]), m);
}

void work()
{
    cin >> sa >> sn;
    int lensn = sn.size();
    if(lensn > 2) n = 100;
    else
    {
        n = 0;
        for(int i = 0; i < lensn; ++i) n = n * 10 + sn[i] - '0';
    }
    printf("%lld\n", cal(1, 10) % 10);
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
//    int T; scanf("%d", &T);
//    while(T--) work();
    work();
//    cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
    return 0;
}

I 限制不互素对的排列

题目描述

输入一个数 ,请构造一个长度为 的排列,使得其中正好有 对相邻的数gcd(最大公约数)大于
排列是指 一共 个数,每个数都出现过且仅出现过 次。例如, 图片说明 是一个排列,而 图片说明图片说明 则不是排列

输入描述:

两个整数 ,用空格隔开。

输出描述:

如果不存在可行的构造方案,输出-1。
否则输出一行 个数,用空格隔开。如果有多组可行的构造方案,输出任意一组即可。

分析:

显然,当 时,直接把前 个偶数提到最前面,其他数按从小到大排列.

时,直接把前 个偶数(除 以外)提到最前面,接着再放 6,然后再放 3,其他数按从小到大排列.

代码实现:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const int M = (int)1e6;
const int N = (int)2e4;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const ll mod = (ll)1e9 + 7;

int n, k;
bool vis[M + 5];

void work()
{
    scanf("%d %d", &n, &k);
    if(n < 6 && k == n / 2) {printf("-1\n"); return;}
    if(k <= n / 2 - 1)
    {
        for(int i = 2; i <= 2 * (k + 1); i += 2)
        {
            printf("%d ", i);
            vis[i] = 1;
        }
        for(int i = 1; i <= n; ++i)
        {
            if(!vis[i]) printf("%d ", i);
        }
        printf("\n");
    }
    else
    {
        for(int i = 2; i <= 2 * k; i += 2)
        {
            vis[i] = 1;
            if(i == 6) continue;
            printf("%d ", i);
        }
        if(vis[6])
        {
            printf("%d %d ", 6, 3);
            vis[3] = 1;
        }
        for(int i = 1; i <= n; ++i)
        {
            if(!vis[i]) printf("%d ", i);
        }
        printf("\n");
    }
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
//    int T; scanf("%d", &T);
//    while(T--) work();
    work();
//    cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
    return 0;
}

J 一群小青蛙呱蹦呱蹦呱

题目描述

有n个格子,每个格子里有一个数,1,2,3,4...n

牛牛放出无穷只青蛙。
第一只青蛙的路线是:1->2->4->8->16->....
第二只青蛙的路线是:1->3->9->27->81->....
第三只青蛙的路线是:1->5->25->125....
第四只青蛙的路线是:1->7->49........
。。。。。。
用数学语言描述,第 只青蛙的路线是首项为1,公比为图片说明 的等比数列,其中图片说明 代表第 个素数。
当青蛙跳到一个格子上,如果这个格子上面有一个数,青蛙就会把这个数吃掉。
牛牛想知道,所有没有被吃掉的数的lcm(最小公倍数 ,Least common multiple)是多少?
由于这个lcm可能非常大,请输出它对图片说明 取模的值。

输入描述:

一个正整数
图片说明

输出描述:

如果所有数都被吃掉了,请输出一个字符串"empty"
否则输出所有没有被吃掉的数的lcm,对图片说明 取模

分析:

显然,没被吃掉的数就是含有至少两个质因子的数.

在统计 lcm 的时候,就让当前质因子的指数尽量大.

代码实现:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const int M = (int)1e8;
const int N = (int)2e4;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const ll mod = (ll)1e9 + 7;

bool is_prime[M + 5];
int prime[M + 5], cnt;

void init()
{
    memset(is_prime, 1, sizeof(is_prime));
    is_prime[0] = is_prime[1] = 0;
    for(int i = 2; i <= M; ++i)
    {
        if(is_prime[i])
        {
            prime[++cnt] = i;
        }
        for(int j = 1; j <= cnt && i * prime[j] <= M; ++j)
        {
            is_prime[i * prime[j]] = 0;
            if(i % prime[j] == 0)
            {
                break;
            }
        }
    }
}

ll quick(ll a, ll b, ll p = mod)
{
//    printf("%lld^%lld\n", a, b);
    ll s = 1;
    while(b)
    {
        if(b & 1) s = s * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return s;
}

void work()
{
    int n; scanf("%d", &n);
    if(n <= 5) {printf("empty\n"); return;}
    ll c = 0, t = 3;
    while(t <= n) ++c, t *= 2;
    ll ans = quick(2, c - 1);
    for(int i = 2; i <= cnt && 2 * prime[i] <= n; ++i)
    {
        c = 0, t = 2;
        while(t <= n) ++c, t *= prime[i];
        ans = ans * quick(prime[i], c - 1) % mod;
    }
    printf("%lld\n", ans);
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
//    int T; scanf("%d", &T);
//    while(T--) work();
    init();
    work();
//    cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
    return 0;
}