2014 ACM/ICPC Asia Regional Xi'an Online
Post Robot http://acm.hdu.edu.cn/showproblem.php?pid=5007
字符串比较
1 #include<cstdio> 2 char a[110]; 3 char A[]="MAI MAI MAI!"; 4 char B[]="SONY DAFA IS GOOD!"; 5 char apple[4][8]={"Apple","iPhone","iPod","iPad"}; 6 char sony[]="Sony"; 7 bool judge(char my[],int s){ 8 for(int i=0;my[i];i++){ 9 if(my[i]!=a[s+i]) return false; 10 } 11 return true; 12 } 13 int main(){ 14 while(gets(a)){ 15 for(int i=0;a[i];i++){ 16 if(judge(sony,i)){ 17 puts(B); 18 continue; 19 } 20 for(int j=0;j<4;j++){ 21 if(judge(apple[j],i)){ 22 puts(A); 23 break; 24 } 25 } 26 } 27 } 28 return 0; 29 }
Boring String Problem http://acm.hdu.edu.cn/showproblem.php?pid=5008
先后缀数组,然后遍历处理出前几个后缀能构成的不同字串,存sum中。然后找第k个的时候二分sum,就知道第k个在第几个后缀中。然后能构成这个串的不一定只有一个,只要字典序大的那些前缀够长,也不是没有可能嘛。所以要往下找一个区间,区间内的height要大于等于这个串的长度,height是公共前缀长度。然后对这个区间求最小的sa。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 typedef __int64 LL; 7 const int M=100010; 8 class Range_Maximum_Query{///区间最值查询离线算法init_o(nlogn),query_o(1) 9 int LOG[M],dpmax[M][20],dpmin[M][20]; 10 public: 11 void init(){///使用类前调用一次即可 12 LOG[0]=-1; 13 for(int i=1;i<M;i++){ 14 LOG[i]=LOG[i>>1]+1; 15 } 16 } 17 void Make_RMQ(int n,int a[]){///传入点的个数,下标1开始 18 for(int i=1;i<=n;i++){ 19 dpmax[i][0]=dpmin[i][0]=a[i]; 20 } 21 for(int j=1;j<=LOG[n];j++){ 22 for(int i=1;i+(1<<j)-1<=n;i++){ 23 dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<(j-1))][j-1]); 24 dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<(j-1))][j-1]); 25 } 26 } 27 } 28 int get_RMQ(int a,int b,bool big){///传入1返回max,传入0返回min 29 int k=LOG[b-a+1]; 30 if(big) 31 return max(dpmax[a][k],dpmax[b-(1<<k)+1][k]); 32 return min(dpmin[a][k],dpmin[b-(1<<k)+1][k]); 33 } 34 }rmqsa,rmqheight; 35 class Suffix_Array { ///后缀数组 36 static const int MV=M;///串长度 37 public: 38 int n,m,i,j,k,p,str[MV],sa[MV],height[MV],Rank[MV],wa[MV],wb[MV],wv[MV],ws[MV];///sa按字典序排序后后缀下标,rank后缀的排名,height排名相邻两个后缀的最长公共前缀 39 bool cmp(int r[],int a,int b,int len) { 40 return r[a]==r[b]&&r[a+len]==r[b+len]; 41 } 42 void buildsa() { 43 int *x=wa,*y=wb; 44 for(i=0; i<m; i++) ws[i]=0; 45 for(i=0; i<n; i++) ws[x[i]=str[i]]++; 46 for(i=1; i<m; i++) ws[i]+=ws[i-1]; 47 for(i=n-1; i>=0; i--) sa[--ws[x[i]]]=i; 48 for(j=p=1; p<n; j<<=1,m=p) { 49 for(p=0,i=n-j; i<n; i++) y[p++]=i; 50 for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; 51 for(i=0; i<m; i++) ws[i]=0; 52 for(i=0; i<n; i++) ws[wv[i]=x[y[i]]]++; 53 for(i=1; i<m; i++) ws[i]+=ws[i-1]; 54 for(i=n-1; i>=0; i--) sa[--ws[wv[i]]]=y[i]; 55 for(swap(x,y),x[sa[0]]=0,p=i=1; i<n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 56 } 57 } 58 void buildheight() { 59 for(i=1; i<=n-1; i++) Rank[sa[i]]=i; 60 for(i=k=0; i<n-1; height[Rank[i++]]=k) 61 for(k?k--:0,j=sa[Rank[i]-1]; str[i+k]==str[j+k]; k++); 62 } 63 int getsa(int id) { 64 return sa[id]; 65 } 66 int getheight(int id) { 67 return height[id]; 68 } 69 int getrank(int id) { 70 return Rank[id]; 71 } 72 void build(char s[],int len,int cl) {///n为字符串长度加一,m为最大字符值加一 73 n=len; 74 m=cl; 75 for(int i=0; i<=len; i++) str[i]=s[i]; 76 str[len]=0; 77 buildsa(); 78 buildheight(); 79 } 80 } gx; 81 char a[M]; 82 LL sum[M]; 83 int main(){ 84 rmqsa.init(); 85 rmqheight.init(); 86 while(~scanf("%s",a)){ 87 int n=strlen(a); 88 gx.build(a,n+1,256); 89 rmqsa.Make_RMQ(n,gx.sa); 90 rmqheight.Make_RMQ(n,gx.height); 91 LL tmp; 92 sum[0]=0; 93 for(int i=1;i<=n;i++){ 94 tmp=n-gx.getsa(i)-gx.getheight(i); 95 sum[i]=sum[i-1]+tmp; 96 } 97 int q; 98 LL v,l=0,r=0; 99 scanf("%d",&q); 100 while(q--){ 101 scanf("%I64d",&v); 102 LL k=(l^r^v)+1; 103 if(k>sum[n]){ 104 l=r=0; 105 puts("0 0"); 106 continue; 107 } 108 int id=lower_bound(sum,sum+n,k)-sum; 109 l=gx.getsa(id); 110 r=n-1; 111 LL cha=sum[id]-k; 112 r-=cha; 113 int len=r-l+1; 114 int L=id+1,R=n; 115 int to=id; 116 while(L<=R){ 117 int mid=(L+R)>>1; 118 if(rmqheight.get_RMQ(id+1,mid,0)>=len){ 119 to=max(to,mid); 120 L=mid+1; 121 } 122 else{ 123 R=mid-1; 124 } 125 } 126 l=rmqsa.get_RMQ(id,to,0); 127 r=l+len-1; 128 l++; 129 r++; 130 printf("%I64d %I64d\n",l,r); 131 } 132 } 133 return 0; 134 }
Game http://acm.hdu.edu.cn/showproblem.php?pid=5011
用的是尼姆博弈的结论,至于为什么和原来的尼姆博弈的结论是一样一样的,好像可以证明。
尼姆博弈的结论是,全部异或起来为零先手输,否则先手赢。说明先手总能通过拿一定量的石头,使得剩下的异或值为零,然后零状态给后手,后手就输了,所以异或不为零,先手能赢。如果全部异或为零,由于先手必须拿至少一个,也就是说剩下的肯定比原来的小一些,那么异或起来肯定不能为零,也就是先手拿完一定会把非零的情况给后手,先手输。
现在多了一种拿法,就是拿完可以分两堆。
分类讨论,如果先手拿了非零的情况,那按照尼姆博弈的拿法,一定能变成零状态给后手,先手赢。
如果先手拿零的情况,拿完以后,剩下的如果不分,就和原来的尼姆博弈一样,一定会输,如果分两块,由于这两块之和小于原来的个数,所以他们异或一定小于原来的个数,所以一定会异或出非零的情况给后手,那么先手输了。
1 #include<cstdio> 2 int main(){ 3 int n,a; 4 while(~scanf("%d",&n)){ 5 int ans=0; 6 while(n--){ 7 scanf("%d",&a); 8 ans^=a; 9 } 10 puts(ans?"Win":"Lose"); 11 } 12 return 0; 13 }
Dice http://acm.hdu.edu.cn/showproblem.php?pid=5012
bfs 4个方向转,把转的置换写出来会比较好。用string表示状态,用map来判重,会方便很多,但是c++会ce,用g++交就ac,也是有点坑。
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #include<map> 5 using namespace std; 6 string S,E; 7 map<string,bool> vis; 8 struct Q{ 9 int step; 10 string sta; 11 }now,pre; 12 queue<Q> q; 13 int zhuan[4][8]={ 14 {2,3,1,0,4,5}, 15 {3,2,0,1,4,5}, 16 {4,5,2,3,1,0}, 17 {5,4,2,3,0,1}, 18 }; 19 int bfs(){ 20 vis.clear(); 21 vis[S]=true; 22 now.sta=S; 23 now.step=0; 24 while(!q.empty()) q.pop(); 25 q.push(now); 26 while(!q.empty()){ 27 pre=q.front(); 28 q.pop(); 29 if(pre.sta==E) return pre.step; 30 for(int i=0;i<4;i++){ 31 for(int j=0;j<6;j++){ 32 now.sta[j]=pre.sta[zhuan[i][j]]; 33 } 34 now.sta.resize(6); 35 if(!vis[now.sta]){ 36 vis[now.sta]=true; 37 now.step=pre.step+1; 38 q.push(now); 39 } 40 } 41 } 42 return -1; 43 } 44 int main(){ 45 char op[2]; 46 while(~scanf("%s",op)){ 47 S=op[0]; 48 for(int i=1;i<6;i++){ 49 scanf("%s",op); 50 S+=op[0]; 51 } 52 E=""; 53 for(int i=0;i<6;i++){ 54 scanf("%s",op); 55 E+=op[0]; 56 } 57 printf("%d\n",bfs()); 58 } 59 return 0; 60 }
Number Sequence http://acm.hdu.edu.cn/showproblem.php?pid=5014
还是贪心的构造,这是参考清华大学team0790 的,每次都构造取反的数,每次都能生成全1的数。这样和最大。
1 #include<cstdio> 2 typedef __int64 LL; 3 const int M=100010; 4 LL sum; 5 int ans[M]; 6 void construct(int n) { 7 sum=0; 8 for(int i=19; i>=0&&n>=0; i--) 9 if(n&(1<<i)) { 10 int s=(2<<i)-1;///s是位数和n一样的全1的数 11 for(int j=s-n; j<=n; j++) {///从n按位取反到n一一赋值,每次都恰好构造出全1. 12 ans[j]=s-j; 13 sum+=s; 14 } 15 n=s-n-1; 16 } 17 if(!n) 18 ans[0]=0; 19 } 20 int main() { 21 int n,a; 22 while(~scanf("%d",&n)) { 23 construct(n); 24 printf("%I64d\n",sum); 25 for(int i=0; i<=n; i++) { 26 scanf("%d",&a); 27 printf("%d ",ans[a]); 28 } 29 puts(""); 30 } 31 return 0; 32 }
根据他们的算法,每个数都能匹配,并且正好能是个排列,所以就直接取反了。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef __int64 LL; 5 const int M=100010; 6 int a[M],b[M],two[32]; 7 int main(){ 8 int n; 9 two[0]=1; 10 for(int i=1;i<=20;i++){ 11 two[i]=two[i-1]*2; 12 } 13 while(~scanf("%d",&n)){ 14 for(int i=0;i<=n;i++){ 15 scanf("%d",&a[i]); 16 b[i]=-1; 17 } 18 for(int i=n;i>=0;i--){ 19 if(b[i]!=-1) continue; 20 int ci=upper_bound(two,two+20,i)-two; 21 int fan=two[ci]-1-i; 22 b[fan]=i; 23 b[i]=fan; 24 } 25 LL ans=0; 26 for(int i=0;i<=n;i++){ 27 ans+=i^b[i]; 28 } 29 printf("%I64d\n",ans); 30 for(int i=0;i<=n;i++){ 31 if(i) printf(" "); 32 printf("%d",b[a[i]]); 33 } 34 puts(""); 35 } 36 return 0; 37 }
233 Matrix http://acm.hdu.edu.cn/showproblem.php?pid=5015
观察可以发现,是序列是递推的,递推10的9次方,所以矩阵快速幂了一下,关键是推出递推矩阵,每一项的都是前几项之和,第一项是233*10+3
1 #include<cstdio> 2 #include<cstring> 3 #define mt(a,b) memset(a,b,sizeof(a)) 4 typedef __int64 LL; 5 const int mod=10000007;///%mod 6 class Matrix { ///矩阵 下标0开始 7 typedef LL typev;///权值类型 8 static const int MV=16;///矩阵长度 9 static const int mod=10000007;///%mod 10 friend Matrix operator *(const Matrix &a,const Matrix &b) { ///矩阵乘法,必须a的列等于b的行 11 Matrix ret; 12 ret.n=a.n; 13 ret.m=b.m; 14 ret.zero(); 15 if(a.m==b.n) { 16 for(int k=0; k<a.m; k++) { 17 for(int i=0; i<a.n; i++) { 18 if(a.val[i][k]) { 19 for(int j=0; j<b.m; j++) { 20 ret.val[i][j]+=a.val[i][k]*b.val[k][j]; 21 ret.val[i][j]%=mod;///看具体需要 22 } 23 } 24 } 25 } 26 } 27 return ret; 28 } 29 friend Matrix operator ^ (Matrix &a,int b) {///必须是n*n方阵才能快速幂 30 Matrix ret; 31 ret.n=ret.m=a.n; 32 ret.unit(); 33 for(; b; a=a*a,b>>=1) { 34 if(b&1) { 35 ret=ret*a; 36 } 37 } 38 return ret; 39 } 40 public: 41 int n,m;///n行m列 42 typev val[MV][MV]; 43 void zero() { 44 mt(val,0); 45 } 46 void unit() { 47 zero(); 48 for(int i=0; i<MV; i++) 49 val[i][i]=1; 50 } 51 } A; 52 LL a[16]; 53 int main(){ 54 int n,m; 55 while(~scanf("%d%d",&n,&m)){ 56 a[0]=3; 57 a[1]=233; 58 for(int i=2;i<=n+1;i++){ 59 scanf("%I64d",&a[i]); 60 } 61 A.zero(); 62 A.val[0][0]=1; 63 A.val[1][0]=1; 64 A.val[1][1]=10; 65 for(int i=2;i<=n+1;i++){ 66 for(int j=1;j<=i;j++){ 67 A.val[i][j]=1; 68 } 69 } 70 A.n=A.m=n+2; 71 A=A^m; 72 LL ans=0; 73 for(int j=0;j<n+2;j++){ 74 ans+=A.val[n+1][j]*a[j]; 75 ans%=mod; 76 } 77 printf("%I64d\n",ans); 78 } 79 return 0; 80 }
Ellipsoid http://acm.hdu.edu.cn/showproblem.php?pid=5017
康神写的模拟退火,我不会,待补。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<string> 6 #include<queue> 7 #include<map> 8 #include<cmath> 9 #include<stack> 10 #include<algorithm> 11 #include<functional> 12 #include<stdarg.h> 13 using namespace std; 14 #ifdef __int64 15 typedef __int64 LL; 16 #else 17 typedef long long LL; 18 #endif 19 20 double esp = 10e-6; 21 22 typedef struct Point { 23 double a,b,c; 24 double l; 25 inline double dis (const Point&p)const { 26 return (p.a-a)*(p.a-a) + (p.b-b)*(p.b-b) +(p.c-c)*(p.c-c); 27 } 28 inline double dis()const { 29 return l; 30 } 31 void init(double a,double b,double c) { 32 this->a=a; 33 this->b=b; 34 this->c=c; 35 l = a*a + b*b + c*c; 36 } 37 inline bool less(const Point&p)const { 38 return l < p.l; 39 } 40 } Point; 41 42 typedef struct { 43 double a,b,c,d,e,f; 44 Point ans; 45 double r; 46 vector<Point> testPoint; 47 bool read() { 48 return ~scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&e,&f); 49 } 50 //随意找到一个局部最优的 51 void getFirstAns() { 52 r = max(a,b); 53 r = max(r,c); 54 ans.init(0,0,sqrt(1/r)); 55 } 56 57 //得到一个范围半径 58 void initRadius() { 59 r = min(a,b); 60 r = min(r,c); 61 r = 1/r; 62 } 63 64 //模拟退火得到答案 65 void solve() { 66 67 int size; 68 bool ok = false; 69 while(r>esp) { 70 ok = false; 71 testPoint.clear(); 72 getTestPoint(); 73 size = testPoint.size(); 74 for(int i=0; i<size; i++) { 75 if(testPoint[i].less(ans)) { 76 ans = testPoint[i]; 77 ok = true; 78 } 79 } 80 if(ok == false) { 81 r = r/2; 82 } 83 84 } 85 } 86 87 88 void getZ(double x, double y) { 89 double z; 90 double a0,b0,c0; 91 a0 = c; 92 b0 = d*y + e*x; 93 c0 = a*x*x + b*y*y + f*x*y - 1; 94 double d0 = b0*b0 - 4*a0*c0; 95 Point point; 96 if(d0 >= 0) { 97 d0 = sqrt(d0); 98 z = (-b0+d0)/(2*a0); 99 point.init(x,y,z); 100 testPoint.push_back(point); 101 z = (-b0-d0)/(2*a0); 102 point.init(x,y,z); 103 testPoint.push_back(point); 104 } 105 } 106 void getY(double x,double z) { 107 double y; 108 double a0,b0,c0; 109 a0 = b; 110 b0 = d*z+f*x; 111 c0 = a*x*x+c*z*z+e*x*z-1; 112 double d0 = b0*b0 - 4*a0*c0; 113 Point point; 114 if(d0 >= 0) { 115 d0 = sqrt(d0); 116 y = (-b0+d0)/(2*a0); 117 point.init(x,y,z); 118 testPoint.push_back(point); 119 y = (-b0-d0)/(2*a0); 120 point.init(x,y,z); 121 testPoint.push_back(point); 122 } 123 } 124 void getX(double y,double z) { 125 double x; 126 double a0,b0,c0; 127 a0 = a; 128 b0 = e*z+f*y; 129 c0 = b*y*y+c*z*z+d*y*z-1; 130 double d0 = b0*b0 - 4*a0*c0; 131 Point point; 132 if(d0 >= 0) { 133 d0 = sqrt(d0); 134 x = (-b0+d0)/(2*a0); 135 point.init(x,y,z); 136 testPoint.push_back(point); 137 x = (-b0-d0)/(2*a0); 138 point.init(x,y,z); 139 testPoint.push_back(point); 140 } 141 } 142 143 //找目前最优解周围的若干点 144 //为了简单,采用以目前最优解为中心的立方体的26*2个点作为周围点 145 //任意确定两个点的坐标,可以用方程求出第三个点的坐标。 146 void getTestPoint() { 147 double x,y,z; 148 x = ans.a; 149 y = ans.b; 150 z = ans.c; 151 for(int i=-1; i<=1; i++) { 152 for(int j=-1; j<=1; j++) { 153 getZ(x+r*i,y+r*j); 154 getX(y+r*i,z+r*j); 155 getY(x+r*i,z+r*j); 156 } 157 158 } 159 } 160 161 double getAns() { 162 return sqrt(ans.l); 163 } 164 165 } Ellipsoid; 166 167 int main() { 168 169 Ellipsoid ellipsoid; 170 while(ellipsoid.read()) { 171 ellipsoid.getFirstAns(); 172 ellipsoid.initRadius(); 173 ellipsoid.solve(); 174 printf("%.8f\n",ellipsoid.getAns()); 175 } 176 177 return 0; 178 }
end