HDU4162 Shape Number

来源:互联网 发布:软件前景 编辑:程序博客网 时间:2024/05/18 17:54

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4162

     看了半天才读懂题意,给定一串数字,原串通过计算每个数字与下一个数字逆时针转动时的距离得到一个新串。(计算方法:如果当前数字小于等于其下一位数字,直接用下一位减去当前数字,否则下一位数字加8减去当前数字。)然后求使该串字典序最小的表示方法。

      首先, 这串数字肯定得作为字符串处理。 新串不难求,主要是求字典序最小的表示方法。比赛时还有半小时结束时才看的这道题,便用了自己能想到的最简单的办法,直接暴力求出该串以最小的字符开头的所有表示方法将它们存在一个字符串数组s[]里,然后对该数组进行sort排序,输出s[0]即可。结果不用想也知道,肯定会TLE。赛后看了一些题解,说是最小表示法的模拟题。这里直接引用一下他人博客里的一句话概括题型。

循环字符串的最小表示法的问题可以这样描述:

                 对于一个字符串S,求S的循环的同构字符串S’中字典序最小的一个。

这里得到新串后,可以设两个变量 i, j。令i = 0, j = 1 分别指向字符串的第一和第二个字符,设 k = 0表示i与j之间的间隔。然后逐位进行字典序的比较,假设已经往后比较了K个字符。

若S[i+k] == S[j+k],k++,继续往后比较下一位。

若S[i+k]  >  S[j+k],i = i+k+1,(因为是求最小表示,所以小的那个不动,移动大的那个。同理,若求最大表示,则大的不变,小的移动。)  k = 0.。(移动后,i,j所指位置重新进行比较,故k = 0,表示已经比较了k个字符。)

若S[i+k] < S[j+k],j = j+k+1,k = 0。原因同上。

若移动后i == j,则j++。(i,j 不能指向同一个字符)

最后返回i,j中较小的那个就好。

注意代码中多次用到了取模运算,因为真的很好用啊啊啊。

#include<iostream>#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<string>#include<algorithm>using namespace std;const int maxn = 300010;char a[maxn],b[maxn];//字符串的最小表示法。int compera(char s[]){    int i = 0, j = 1, k = 0, len = strlen(s);    while(i < len && j < len && k < len)    {        if(s[i+k] == s[j+k]) k++;        else{            if(s[i+k] > s[j+k]) i = i+k+1;            else if(s[j+k] > s[i+k]) j = j+k+1;            if(i == j) j++;            k = 0;        }    }    return i < j ? i : j;}int main(){    while(~scanf("%s",a))    {        int len = strlen(a);        for(int i = 0; i < len-1; i++)//由已知串a 得到新串 b;        {            b[i] = (a[i+1] - a[i] + 8) % 8 + '0';//            cout << b[i];        }        b[len-1] = (a[0] - a[len-1] + 8) % 8 + '0';//        cout << b[len-1] << endl;        b[len] = 0;        int ans = compera(b);//得到最小表示法所得的最小字符串对应的第一个字符的下标。        for(int i = ans; i < ans+len;i++)        {            printf("%c",b[(i+len)%len]);//直接输出就好。        }        printf("\n");    }    return 0;}




0 0
原创粉丝点击