【洛谷1415】拆分数列
原题:
序列长度<=500
首先需要灵稽一动,发现一条性质
因为序列上的数字固定,所以可以用两个数l和r来表示一段数[l,r],也就是说划分后的每一个数只需用两个端点来表示
我的做法是把[l,r]视为一个状态,然后n^3处理找出所有可转移的状态对,建图,跑两遍bfs……
看上去挺乱搞的,居然搞过了 = =b
实际上正解和bfs记忆化差不多,属于典型的bfs转dp的类型
dp不过是用循环枚举状态来代替状态图中的边
只要发现了一段数可以用两个端点表示的性质就能写了,例如用f[i]表示以i为终点的数的左端点下标最少是多少
判断两个数的大小可以直接第三重循环,这样dp的复杂度也是n^3的
其实直接建图跑bfs是过不了的,因为边数太多了
不过大概想象了一下,规定参与连边的状态长度不能超过50,就直接跑过了 XD
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<time.h> 5 using namespace std; 6 struct edg{int nxt,y;}e[21000000]; int lk[251000],ltp=0; 7 void ist(int x,int y){ 8 e[++ltp]=(edg){lk[x],y}; lk[x]=ltp; 9 e[++ltp]=(edg){lk[y],x}; lk[y]=ltp; 10 //cout<<x<<" "<<y<<endl; 11 } 12 char s[510]; int a[510],n; 13 int q[251000],hd=0; 14 bool clr[251000]; 15 int ans=0; 16 int gtid(int x,int y){ return (x-1)*n+y-1;} 17 void bfs1(){ 18 int N=gtid(n,n); 19 for(int i=0;i<=N;++i) clr[i]=false; 20 hd=0; 21 for(int i=1;i<=n;++i){ 22 q[++hd]=gtid(1,i); 23 clr[gtid(1,i)]=true; 24 } 25 for(int k=1;k<=hd;++k){ 26 //printf("(%d, %d)\n",q[k]/n+1,q[k]%n+1); 27 for(int i=lk[q[k]];i;i=e[i].nxt){ 28 if(e[i].y/n+1==q[k]%n+1+1 && !clr[e[i].y]){ 29 clr[e[i].y]=true; 30 q[++hd]=e[i].y; 31 } 32 } 33 } 34 } 35 void bfs2(){ 36 int N=gtid(n,n); 37 for(int i=0;i<=N;++i) clr[i]=false; 38 //注意id可以是0 39 q[hd=1]=gtid(ans,n); 40 clr[gtid(ans,n)]=true; 41 //for(int i=ans-1;i>=1;--i)if(!a[i]){ 42 for(int i=ans-1;i>=1 && !a[i];--i){ 43 q[++hd]=gtid(i,n); 44 clr[gtid(i,n)]=true; 45 } 46 for(int k=1;k<=hd;++k){ 47 //printf("(%d, %d)\n",q[k]/n+1,q[k]%n+1); 48 for(int i=lk[q[k]];i;i=e[i].nxt)if(e[i].y%n+1==q[k]/n+1-1 && !clr[e[i].y]){ 49 clr[e[i].y]=true; 50 q[++hd]=e[i].y; 51 } 52 } 53 } 54 bool chck(int x,int y,int z){ 55 int l1=x,l2=y+1; 56 for(;!a[l1];++l1); 57 for(;!a[l2];++l2); 58 if(y-l1+1<z-l2+1) return true; 59 if(y-l1+1>z-l2+1) return false; 60 for(int i=0;l1+i<=y;++i){ 61 if(a[l1+i]<a[l2+i]) return true; 62 if(a[l1+i]>a[l2+i]) return false; 63 } 64 return false; 65 } 66 int main(){ 67 //int t0=clock(); 68 69 scanf("%s",s+1); n=strlen(s+1); 70 for(int i=1;i<=n;++i) a[i]=s[i]-'0'; 71 /* 72 n=500; 73 for(int i=1;i<=n;++i) a[i]=9; 74 cout<<"input: "<<clock()-t0<<endl; 75 t0=clock(); 76 */ 77 for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j) 78 //for(int k=i;k<j;++k)if(chck(i,k,j)){ 79 for(int k=i;k<j;++k)if(k-i+1<=50 && j-k<=50 && chck(i,k,j)){ 80 ist(gtid(i,k),gtid(k+1,j)); 81 //printf("(%d, %d) -> (%d, %d)\n",i,k,k+1,j); 82 } 83 84 //cout<<"insert: "<<clock()-t0<<endl; 85 //t0=clock(); 86 87 bfs1(); 88 for(int i=n;i>=1;--i)if(clr[gtid(i,n)]){ 89 ans=i; 90 break; 91 } 92 93 //cout<<"bfs1: "<<clock()-t0<<endl; 94 //t0=clock(); 95 96 bfs2(); 97 int l=1,r=0; 98 for(int i=n;i>=1;--i)if(clr[gtid(1,i)]){ 99 r=i; 100 break; 101 } 102 103 //cout<<"bfs2: "<<clock()-t0<<endl; 104 //t0=clock(); 105 106 hd=0; //注意如果加了r!=n的判断hd可能不会被重制 107 if(r!=n) q[hd=1]=r; 108 for(;r<n;){ 109 int mx=0; 110 for(int i=lk[gtid(l,r)];i;i=e[i].nxt)if(e[i].y/n+1==r+1 && clr[e[i].y]) 111 mx=max(mx,e[i].y%n+1); 112 l=r+1,r=mx; 113 if(r==n) break; 114 q[++hd]=r; 115 } 116 117 //cout<<"ans: "<<clock()-t0<<endl; 118 //t0=clock(); 119 120 for(int i=1,j=1;i<=n;++i){ 121 printf("%d",a[i]); 122 if(j<=hd && i==q[j]){ 123 printf(","); 124 ++j; 125 } 126 } 127 printf("\n"); 128 /* 129 cout<<"output: "<<clock()-t0<<endl; 130 for(;;){ 131 } 132 */ 133 return 0; 134 }