【模拟】Vijos P1005 超长数字串
题目链接:
题目大意:
无限的正整数按顺序拼接成字符串S(S=12345678910111213...),给你一个字符串A(len<=200)求这个字符串在S中最早出现的位置。
(答案超过long long ,无法用KMP,不要相信标签)
题目思路:
【模拟】
这题简直了!!!!!!大模拟啊。细节超级多。疯狂TLE+WA+RE了17次才AC。
第一次写了一整天没写过,放了好久,昨天又写了一整天(哎效率低下。)
首先分两种普遍的情况和两种特殊情况考虑。
普遍情况一是S串是由三段组成,头,尾和中间数字串,头尾可能不完全。这时候枚举中间数字串的长度和起始位置,就可以判断出最早出现的数字
(如:123[98 12399 124]00 99[8 999 1000 10]01 等)
(一开始我是想把这个再分情况考虑,发现有进位什么的太麻烦了后来直接把这个数压到高精度中,先-1判断和头是否匹配,再每次+1判断和后面的字符串匹不匹配,尾部同理)
普遍情况二是S串是由两段组成,前面的数字的尾部和后面的数字的头部组成,这时要枚举重叠部分的长度和断开的位置。
(如:1[2 1]3 123[699 1237]00 60211602应该是 1[6021 1602]2 而不是[60211 602]12)
(一开始我忘记了这种情况WA了好久。。感觉自己好蠢。)
特殊情况一是全为0的情况,这是都不符合上面的情况,就需要在头部再添上一个1,肯定是最早出现的。
特殊情况二是全为9的情况,除了单个9是9以外,两位数以上的9都可以拆成 8[9999... 9]0000... 这个答案明显比[9999...] 10000...优。
(不知道自己还有没有漏情况,希望没有吧,望指教。)
1 // 2 //by coolxxx 3 //#include<bits/stdc++.h> 4 #include<iostream> 5 #include<algorithm> 6 #include<string> 7 #include<iomanip> 8 #include<map> 9 #include<memory.h> 10 #include<time.h> 11 #include<stdio.h> 12 #include<stdlib.h> 13 #include<string.h> 14 //#include<stdbool.h> 15 #include<math.h> 16 #define min(a,b) ((a)<(b)?(a):(b)) 17 #define max(a,b) ((a)>(b)?(a):(b)) 18 #define abs(a) ((a)>0?(a):(-(a))) 19 #define lowbit(a) (a&(-a)) 20 #define sqr(a) ((a)*(a)) 21 #define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b)) 22 #define mem(a,b) memset(a,b,sizeof(a)) 23 #define eps (1e-8) 24 #define J 10 25 #define mod 1000000007 26 #define MAX 0x7f7f7f7f 27 #define PI 3.14159265358979323 28 #define N 404 29 using namespace std; 30 typedef long long LL; 31 int cas,cass; 32 int n,m,lll,ans; 33 double anss; 34 char s[N]; 35 int a[N],b[N],t[N],c[N]; 36 void gjdchange(int a[],int l,int r)//l~r中间的字符转化为高精度数a 37 { 38 int i; 39 mem(t,0); 40 t[0]=r-l+1; 41 for(i=1;i<=r-l+1;i++) 42 t[i]=s[r-i+1]-'0'; 43 memcpy(a,t,sizeof(t)); 44 } 45 void plu(int a[])//高精度a+1 46 { 47 int i; 48 for(i=1,a[1]++;a[i]>=J;i++) 49 a[i]-=J,a[i+1]++; 50 a[0]=max(a[0],i); 51 } 52 void dec(int a[])//高精度a-1 53 { 54 int i; 55 for(i=1,a[1]--;a[i]<0;i++) 56 a[i]+=J,a[i+1]--; 57 while(!a[a[0]] && a[0]>1)a[0]--; 58 } 59 int gjdbigger(int a[],int b[])//高精度a和高精度b比大小 1:a>b 0:a<b -1:a=b 60 { 61 if(a[0]!=b[0])return a[0]>b[0]; 62 int i; 63 for(i=a[0];i;i--)if(a[i]!=b[i])return a[i]>b[i]; 64 return -1; 65 } 66 bool tou(int i,int len)//判断头部是否满足 67 { 68 int ii; 69 dec(a); 70 for(ii=1;ii<=a[0] && i-ii;ii++) 71 if(a[ii]!=s[i-ii]-'0')return 0; 72 return 1; 73 } 74 void gjdjia(int a[],int b[],int c[])//高精度a+高精度b,答案存在高精度c里 75 { 76 int i; 77 mem(t,0); 78 t[0]=max(a[0],b[0]); 79 for(i=1;i<=t[0];i++) 80 t[i]=a[i]+b[i]; 81 for(i=1;i<=t[0];i++) 82 t[i+1]+=t[i]/J,t[i]%=J; 83 while(t[t[0]+1])t[0]++; 84 while(!t[t[0]] && t[0]>1)t[0]--; 85 memcpy(c,t,sizeof(t)); 86 } 87 void gjdjian(int a[],int b[],int c[])//高精度a-高精度b,答案存在高精度c里 88 { 89 int i; 90 mem(t,0); 91 t[0]=a[0]; 92 for(i=1;i<=t[0];i++) 93 t[i]=a[i]-b[i]; 94 for(i=1;i<=t[0];i++) 95 if(t[i]<0)t[i+1]--,t[i]+=J; 96 for(i=1;i<=t[0];i++) 97 t[i+1]+=t[i]/J,t[i]%=J; 98 while(t[t[0]+1])t[0]++; 99 while(!t[t[0]] && t[0]>1)t[0]--; 100 memcpy(c,t,sizeof(t)); 101 } 102 void gjdchengdjd(int a[],int b,int c[])//高精度a*单精度b,答案存在高精度c里 103 { 104 int i; 105 mem(t,0); 106 t[0]=a[0]+3; 107 for(i=1;i<=a[0];i++) 108 t[i]=a[i]*b; 109 for(i=1;i<=t[0];i++) 110 t[i+1]+=t[i]/J,t[i]%=J; 111 while(t[t[0]+1])t[0]++; 112 while(!t[t[0]] && t[0]>1)t[0]--; 113 memcpy(c,t,sizeof(t)); 114 } 115 void cal(int len,int head)//已知a为第一个完整出现的数字,len为长度,head为出现的位置 116 { 117 int i,j; 118 int tmp[N]; 119 mem(tmp,0); 120 //gjdchange(a,head,head+len-1); 121 b[0]=1;b[1]=9;c[0]=1;c[1]=0; 122 for(i=1;i<a[0];i++) 123 { 124 gjdchengdjd(b,i,tmp); 125 gjdjia(c,tmp,c); 126 b[b[0]+1]=9;b[b[0]++]=0; 127 } 128 b[b[0]]=0; 129 b[0]=a[0];b[b[0]]=1; 130 for(i=1;i<a[0];i++)b[i]=0; 131 gjdjian(a,b,a); 132 gjdchengdjd(a,len,b); 133 gjdjia(c,b,c); 134 mem(b,0); 135 b[0]=1;b[1]=head-2; 136 while(b[b[0]]>=J)b[b[0]+1]=b[b[0]]/J,b[b[0]++]%=J; 137 gjdjian(c,b,c); 138 } 139 void work(int &len,int &head)//从中间断开分成两个数字的情况 140 { 141 int i,j,l; 142 if(len<=n) 143 gjdchange(a,head,head+len-1); 144 else a[0]=MAX; 145 b[0]=0; 146 for(l=0;l<=(n+1)/2+1;l++)//最终长度n-l 147 { 148 for(j=1;j<=l;j++) 149 if(s[j]!=s[n-l+j])break; 150 if(j<=l)continue; 151 for(i=l+2;i<=n-l;i++) 152 { 153 b[0]=0; 154 for(j=i-1;j;j--)b[++b[0]]=s[j]-'0'; 155 for(j=n-l;j>=i;j--)b[++b[0]]=s[j]-'0'; 156 plu(b); 157 if(b[b[0]]==0)continue; 158 for(j=0;j<b[0] && i+j<=n;j++) 159 if(b[b[0]-j]!=s[i+j]-'0')break; 160 if(j<b[0] && i+j<=n)continue; 161 if(gjdbigger(a,b)){memcpy(a,b,sizeof(b));len=n-l;head=i;} 162 } 163 } 164 } 165 bool all9()//长度大于2且全是9的特殊情况 拆成8999999999...+9000000000... 166 { 167 int i; 168 gjdchange(b,1,n); 169 for(i=1;i<=b[0];i++)if(b[i]!=9)return 0; 170 if(b[0]==1)return 0; 171 b[b[0]]=8;plu(b); 172 memcpy(a,b,sizeof(b)); 173 return 1; 174 } 175 bool all0()//全是0的特殊情况 1+00000000... 176 { 177 int i; 178 gjdchange(b,1,n); 179 for(i=1;i<=b[0];i++)if(b[i]!=0)return 0; 180 b[++b[0]]=1; 181 memcpy(a,b,sizeof(b)); 182 return 1; 183 } 184 void gjdprint(int a[])//输出高精度a 185 { 186 int i; 187 printf("%d",a[a[0]]); 188 for(i=a[0]-1;i;i--) 189 printf("%d",a[i]); 190 puts(""); 191 } 192 int main() 193 { 194 #ifndef ONLINE_JUDGE 195 freopen("1.txt","r",stdin); 196 // freopen("2.txt","w",stdout); 197 #endif 198 int i,j,k,l; 199 // for(scanf("%d",&cas);cas;cas--) 200 // for(scanf("%d",&cas),cass=1;cass<=cas;cass++) 201 while(~scanf("%s",s+1)) 202 // while(~scanf("%d",&n)) 203 { 204 s[0]='.'; 205 n=strlen(s)-1; 206 for(l=1;l<=n;l++) 207 { 208 for(i=1;i<=l && i+l-1<=n;i++) 209 { 210 gjdchange(a,i,i+l-1); 211 if(a[a[0]]==0)continue;//前导0不符合要求 212 if(i!=1) 213 { 214 if(!tou(i,l))continue; 215 plu(a); 216 } 217 for(j=i+l;j<=n;j+=a[0]) 218 { 219 plu(a); 220 for(k=0;j+k<=n && k<a[0];k++) 221 { 222 if(a[a[0]-k]!=s[j+k]-'0')break; 223 } 224 if(j+k>n || k<a[0])break; 225 } 226 if(j+k>n)break; 227 if(j>n)break; 228 } 229 if(i<=l && i+l-1<=n)break; 230 } 231 //以上是将字符串拆成三段枚举,头,尾和中间的数字 232 work(l,i); 233 if(all9())cal(n,n); 234 else if(all0())cal(n+1,0); 235 else cal(l,i); 236 gjdprint(c); 237 } 238 return 0; 239 } 240 /* 241 // 242 243 // 244 */