HDU Problem - 5976 Detachment(逆元,阶乘打表,数学)

题目链接

Problem Description

In a highly developed alien society, the habitats are almost infinite dimensional space.In the history of this planet,there is an old puzzle.You have a line segment with x units’ length representing one dimension.The line segment can be split into a number of small line segments: a 1 , a 2 , … (x= a 1 + a 2 +…) assigned to different dimensions. And then, the multidimensional space has been established. Now there are two requirements for this space: 1.Two different small line segments cannot be equal ( a i a j when i≠j).2.Make this multidimensional space size s as large as possible (s= a 1 a 2 *…).Note that it allows to keep one dimension.That’s to say, the number of ai can be only one.Now can you solve this question and find the maximum size of the space?(For the final number is too large,your answer will be modulo 10^9+7)

Input

The first line is an integer T,meaning the number of test cases.Then T lines follow. Each line contains one integer x.1≤T≤10^6, 1≤x≤10^9

Output

Maximum s you can get modulo 10^9+7. Note that we wants to be greatest product before modulo 10^9+7.

Sample Input

1
4

Sample Output

4

AC

  • 一个数字分成多个不相同的数字相乘,首先分成1不合理,因为1乘以一个数结果不增加,从2枚举所有X可以分出的连续数字,最后可能会剩余几个数字,可以把剩余的数字看成N个1,剩下任务就是将这N个1分出去,从最后一个数字开始往前每个数字加1,这样能保证连续的情况下乘积最大,这样就有两种情况,剩下的数字能分完和不能分完(多了个1),例如8 = 2 +3 +3,最后一个3分给前面两个数字之后多了个1,这个1就分到最后一个数字上,例如8 = 2 +3 +2,这样刚好分完
  • 数据规模大,一共有1e6的询问,时间要求在2秒,所以每次最好O(1)算出结果,观察上面的思路,最后的得到的数字,就是部分连续的数字相乘,可以用阶乘打表处理,另外存在相除的情况,所以也要逆元打表,判断最后一个数字是否能分完,需要用到sum前缀
#include <iostream>
#include <stdio.h>
#include <map>
#include <vector>
#include <set>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 100005
#define ll  long long
using namespace std;
ll mod = 1e9 + 7;
ll inv[N], sum[N], jie[N];
void init() {
    // 逆元打标 
    inv[1] = 1;
    for (int i = 2; i < N; ++i) {
        inv[i] = inv[mod % i] * (mod - mod / i) % mod;
    }
    // sum记录前缀之和 
    sum[2] = 2;
    for (int i = 3; i < N; ++i) {
        sum[i] = sum[i - 1] + i;
    }
    // 阶乘打表 
    jie[2] = 2;
    for (int i = 3; i < N; ++i) {
        jie[i] = jie[i - 1] * i;
        jie[i] %= mod;
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    init();
    int t;
    scanf("%d", &t) ;
    while (t--) {
        ll x, ans;
        scanf("%lld", &x);
        // 找到第一个大于等于sum的位置 
        int pos = lower_bound(sum, sum + N, x) - sum;
        while (sum[pos] > x)    pos--;

        int cha = x - sum[pos];

        // X刚好分完 
        if (cha == 0) 
            ans = jie[pos];
        // 多出来pos个1 (不能分完) 
        if (cha == pos) 
            ans = (jie[pos] * inv[2] % mod) * (pos + 2) % mod;
        //  多出来的1小于pos(可以分完) 
        if (cha < pos)
            ans = jie[pos + 1] * inv[pos + 1 - cha] % mod;
        // X小于5,保持原来的长度最好 
        if (ans == 0)   ans = x;    
        printf("%lld\n", ans);  
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henuyh/article/details/82151039