HDU6223 && 2017沈阳ICPC: G. Infinite Fraction Path——特殊图&&暴力

题意

给定一个数字串,每个位子都能向(i*i+1)%n的位子转移,输出在路径上、字典序最大的、长度为n的串($n \leq 150000$)。

分析

先考虑一个暴力的方法,考虑暴力每个x,然后O(n)判定形成的字符串字典序是否比当前的最优解要大,复杂度O(n²),显然大家都会做。

而本题中有个结论:没有必要每次O(n),只要前100个字符一样,那么后面的一定都一样!所以>500直接break,复杂度O(500n), 可以过!

理解:对于所有的下标k,k向(k*k+1)%n连一条有向边,最后可以得到若干棵基环树构成的森林,这个森林有三个性质:①基环树特别的多;②每棵基环树环特别的小;③叶子巨多;这样子的话,字符串一定会很快进入一个环,两个字符串前面相等后面就一定都相等了.

回头想一下,当时就应该“乱搞”,这种图肯定比较简单,因为出题人也没法特意搞极端情况,这是由数字的性质决定的。

#include
using namespace std;

const int maxn = 150000 + 10;
char s[maxn];
int n;
int nxt[maxn];

int main()
{
    int T, kase=0;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        scanf("%s", s);
        for(int i = 0;i < n;i++)  nxt[i] = (1LL * i * i + 1) % n;
        char start = '0';
        for(int i = 0;i < n;i++)  if(s[i] > start)  start = s[i];
        int res = 0;
        for(int i = 0;i < n;i++)
        {
            int cur = i, p = res;
            if(s[i] == start)
            {
                for(int j = 1;j < 100;j++)
                {
                    if(s[cur] < s[p])  break;
                    if(s[cur] > s[p]) {res = i; break;}
                    cur = nxt[cur];
                    p = nxt[p];
                }
            }
        }
        printf("Case #%d: ", ++kase);
        for(int i = 0;i < n;i++)
        {
            printf("%c", s[res]);
            res = nxt[res];
        }
        printf("\n");
    }
    return 0;
}

 

 

参考链接:https://blog.csdn.net/Jaihk662/article/details/81987188?tdsourcetag=s_pctim_aiomsg

你可能感兴趣的:(HDU6223 && 2017沈阳ICPC: G. Infinite Fraction Path——特殊图&&暴力)