2017ICPC沈阳现场赛G(倍增思想)

Infinite Fraction Path

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 279    Accepted Submission(s): 34


Problem Description
The ant Welly now dedicates himself to urban infrastructure. He came to the kingdom of numbers and solicited an audience with the king. He recounted how he had built a happy path in the kingdom of happiness. The king affirmed Welly’s talent and hoped that this talent can help him find the best infinite fraction path before the anniversary.
The kingdom has N cities numbered from 0 to N - 1 and you are given an array D[0 ... N - 1] of decimal digits (0 ≤ D[i] ≤ 9, D[i] is an integer). The destination of the only one-way road start from the i-th city is the city labelled ( i2  + 1)%N.
A path beginning from the i-th city would pass through the cities  u1,u2,u3 , and so on consecutively. The path constructs a real number A[i], called the relevant fraction such that the integer part of it is equal to zero and its fractional part is an infinite decimal fraction with digits D[i], D[ u1 ], D[ u2 ], and so on.
The best infinite fraction path is the one with the largest relevant fraction
 

Input
The input contains multiple test cases and the first line provides an integer up to 100 indicating to the total numberof test cases.
For each test case, the first line contains the integer N (1 ≤ N ≤ 150000). The second line contains an array ofdigits D, given without spaces.
The summation of N is smaller than 2000000.
 

Output
For each test case, you should output the label of the case first. Then you are to output exactly N characters which are the first N digits of the fractional part of the largest relevant fraction.
 

Sample Input
  
  
4 3 149 5 12345 7 3214567 9 261025520
 

Sample Output
  
  
Case #1: 999 Case #2: 53123 Case #3: 7166666 Case #4: 615015015
 

Source
 

Recommend

jiangzijing2015


解题思路:令ans[i][j]为以i为起点,长度为2^j的路径就行,类似于后缀数组中的基数排序一样,我这里做了一点变化,每次得到新的rank时,用上一次的两个关键字来计算,用第一关键字乘上一个比最大的第二关键字大的数就行,然后把这个乘积加上第二关键字就行,然后排序,得到新的rank,复杂度(O(n * logn * logn)),其实应该还有更好的解法,就是用后缀数组里面的基数排序中的思想就行。


#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 150000 + 10;
int N;
char D[maxn];
int Nxt[maxn];
int dp[maxn];
int Rank[maxn];
char res[maxn];
int temp[maxn];
struct node
{
    int id;
    LL value;
    bool operator <(const node &res) const
    {
        return value < res.value;
    }
} Node[maxn];
int main()
{
    int T;
    //freopen("C:\\Users\\creator\\Desktop\\in1.txt","r",stdin) ;
    //freopen("C:\\Users\\creator\\Desktop\\out.txt","w",stdout) ;
    scanf("%d", &T);

    int Case = 1;
    while(T--)
    {
        scanf("%d", &N);
        scanf("%s", D);
        for(int i = 0; i < N; i++)
        {
            LL x = (LL)i * (LL)i + 1;
            x %= (LL)N;
            Nxt[i] = x;
            dp[i] = i;
        }
        if(N == 1)
        {
            printf("Case #%d: %s\n", Case++, D);
            continue;
        }
        for(int i = 0; i < N; i++)
        {
            Rank[i] = (D[i] - '0');
        }
        int w = 1;
        int ans = -1;
        while(true)
        {
            for(int i = 0; i < N; i++)
            {
                Node[i].id = i;
                LL Nxt1 = dp[i];
                Nxt1 = Nxt[Nxt1];
                temp[i] = dp[Nxt1];
                Node[i].value = (LL)Rank[i] * (LL)(maxn + 1) + (LL)Rank[Nxt1];
            }
            sort(Node, Node + N);
            int p = -1;
            for(int i = 0; i < N; i++)
            {
                dp[i] = temp[i];
                int id = Node[i].id;
                if(i == 0) Rank[id] = ++p;
                else
                {
                    if(Node[i].value == Node[i - 1].value) Rank[id] = p;
                    else Rank[id] = ++p;
                }
            }
            if((1<<w) >= N)
            {
                LL Max = -1;
                for(int i = 0; i < N; i++)
                {
                    if(Rank[i] > Max)
                    {
                        Max = Rank[i];
                        ans = i;
                    }
                }
                break;
            }
            w++;
        }
        int depth = 0;
        res[depth++] = D[ans];
        while(depth < N)
        {
            ans = Nxt[ans];
            res[depth++] = D[ans];
        }
        res[N] = '\0';
        printf("Case #%d: %s\n", Case++, res);
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值