最强阵容加强版

1613: 最强阵容加强版

时间限制: 1 Sec  内存限制: 128 MB

题目描述

拿着新换来的英雄卡,小李满心欢喜的准备和同学们PK一下。
他们的游戏规则非常简单,双方把自己的牌绕成一圈,然后指定一个起点,从该张牌开始顺时针方向往后取,谁取出的字符串字典序更小(从左到右开始比较,碰到第一个不一样的字符进行比较,比较规则为a<b<…<z)谁将获得胜利。具体规则可参考样例。虽然现在小李的牌已经很好了,但是你能不能帮他快速算出起始位置,使得他能够派出最强阵容。

 

输入

第一行n,表示共有n张牌。
第二行共n个用一个空格隔开的小写字母,表示给定的一圈牌起始序列。

 

输出

仅一个整数,能获得最小字典序字符串的起点位置。如果有多个位置开始的字符串一样,则输出最小的那个位置,且第一个位置从1开始。

 

样例输入

4 b c a b

样例输出

3

提示

 

【样例说明】 

四个位置取出的字符串分别为bcab,cabb,abbc,bbca,显然最小位置是3。

【数据规模】 

30%的数据,1<=n<=10

60%的数据,1<=n<=1000

100%的数据,1<=n<=300000

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 int a[600005];
 6 int main()
 7 {
 8     int n; scanf("%d",&n); 
 9     int ch; scanf("%c",&ch);
10     for (int i=1;i<n;i++) scanf("%c ",&a[i]),a[i+n]=a[i];
11     scanf("%c",&a[n]); a[n+n]=a[n];
12     int i=1,j=2;
13     while (j<=n){
14         int k;
15         for (k=0;k<n;k++)
16             if (a[i+k]<a[j+k]){
17                 j=j+k+1; break;
18             } else if (a[i+k]>a[j+k]){
19                 i=j; j=j+1; break;
20             }
21         if (k==n) j=j+k;
22     }
23     printf("%d",i);
24 }
View Code
 1 #include<iostream>  
 2 #include<cstdio>  
 3 #include<cmath>  
 4 #include<cstring>  
 5 #include<algorithm>  
 6 using namespace std;  
 7 #define P 27  
 8 #define P1 1795876273  
 9 #define P2 2001122927  
10 #define N 600005  
11 long long a[N],f1[N],f2[N],fp1[N],fp2[N];  
12 #define F1(i,j) mo(f1[j]-f1[i-1]*fp1[j-i+1],P1)  
13 #define F2(i,j) mo(f2[j]-f2[i-1]*fp2[j-i+1],P2)  
14 int mo(long long a,int q)
15 {
16     a=a%q; if (a<0) a+=q;
17     return a;
18 }
19 int check(int i,int j,int k){  
20     if (k==1) {  
21         if (a[i]<=a[j]) return 0;  
22         return 1;  
23     }  
24     //cout<<i<<" "<<j<<" "<<i+k/2-1<<" "<<j+k/2-1<<endl;
25     if (F1(i,i+k/2-1)==F1(j,j+k/2-1) && F2(i,i+k/2-1)==F2(j,j+k/2-1))  
26         check(i+k/2,j+k/2,(k+1)/2);
27     else check(i,j,k/2);
28 }  
29 int main()  
30 {  
31     int n; scanf("%d",&n);   
32     int ch; scanf("%c",&ch);  
33     for (int i=1;i<n;i++) scanf("%c ",&a[i]),a[i+n]=a[i];  
34     scanf("%c",&a[n]); a[n+n]=a[n];  
35     for (int i=1;i<=n+n;i++) a[i]-=96;  
36     for (int i=1;i<=n+n;i++) f1[i]=mo(f1[i-1]*P+a[i],P1);  
37     for (int i=1;i<=n+n;i++) f2[i]=mo(f2[i-1]*P+a[i],P2);  
38     fp1[0]=1; fp2[0]=1;
39     for (int i=1;i<=n+n;i++) fp1[i]=mo(fp1[i-1]*P,P1);
40     for (int i=1;i<=n+n;i++) fp2[i]=mo(fp2[i-1]*P,P2);
41     //cout<<check(1,2,n)<<" "<<check(2,3,n)<<" "<<check(3,4,n);
42     int ans=1;  
43     for (int i=2;i<=n;i++)  
44         if (check(ans,i,n)) ans=i;  
45     printf("%d",ans);  
46 }  
View Code

 

转载于:https://www.cnblogs.com/SXia/p/7612103.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值