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 }
View Code

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
",l,r);
131         }
132     }
133     return 0;
134 }
View Code

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 }
View Code

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
",bfs());
58     }
59     return 0;
60 }
View Code

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
",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 }
View Code

根据他们的算法,每个数都能匹配,并且正好能是个排列,所以就直接取反了。

 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
",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 }
View Code

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
",ans);
78     }
79     return 0;
80 }
View Code

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
",ellipsoid.getAns());
175     }
176 
177     return 0;
178 }
View Code

end

原文地址:https://www.cnblogs.com/gaolzzxin/p/3971423.html