hdu 4759 Poker Shuffle(规律,大数,位)

很神奇的一道题。

 

参考:http://www.cnblogs.com/kuangbin/p/3346037.html

题意:


题目意思很简单。

就是洗牌,抽出奇数和偶数,要么奇数放前面,要么偶数放前面。 总共2^N张牌。需要问的是,给了A X B Y  问经过若干洗牌后,第A个位置是X,第B个位置是Y 是不是可能的。 

 

题目给的牌编号是1开始的,先转换成0开始。一开始位置是0~2^N-1.  对应的牌是0~2^N-1

首先来看每次洗牌的过程。

 

对于第一种洗牌:将奇数放前面,偶数放后面。其实每个位置数的变化就是相当于循环右移一位,然后高位异或1.

对于第二种洗牌:讲偶数放前面,奇数放后面。其实每个位置数的变化就是相当于循环右移一位,然后高位异或0. 

所以经过若干次洗牌,可以看成是循环右移了K位,然后异或上一个数。 

 

所以对于题目的查询:首先将A X B Y都减一。  然后枚举X,Y循环右移了K位以后,能不能同时异或上相同的数得到A,B 

需要大数,然后转化成二进制就可以解决了。循环右移X,Y,然后判断A ^ X 是不是等于 B ^ Y 

 ”

问题1:为什么是相同的数?

 因为对k个数的操作要么是第一种洗牌,要么是第二种洗牌,也就是说对每个数最高位异或的数(0或1)是一样的。而这个异或操作会随该位的移动而移动,累积。

 

问题2:为什么只需要枚举n次?

因为2^n 只有n位,循环右移n位之后变为原数。

 

PS:

1、有点压缩的味道。

2、a[0]为低位,a[n]为高位。

 

ExpandedBlockStart.gif
  1  #pragma comment(linker, "/STACK:1024000000,1024000000")
  2 #include <stdio.h>
  3 #include < string.h>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <vector>
  7 #include <queue>
  8 #include < set>
  9 #include <map>
 10 #include < string>
 11 #include <math.h>
 12 #include <stdlib.h>
 13 #include <time.h>
 14  using  namespace std;
 15 
 16  /*
 17   * 完全大数模板
 18   * 输出cin>>a
 19   * 输出a.print();
 20   * 注意这个输入不能自动去掉前导0的,可以先读入到char数组,去掉前导0,再用构造函数。
 21    */
 22  #define MAXN 9999
 23  #define MAXSIZE 1010
 24  #define DLEN 4
 25 
 26  class BigNum
 27 {
 28  public:
 29      int a[ 500];   // 可以控制大数的位数
 30       int len;
 31  public:
 32     BigNum(){len= 1;memset(a, 0, sizeof(a));}   // 构造函数
 33      BigNum( const  int);      // 将一个int类型的变量转化成大数
 34      BigNum( const  char*);    // 将一个字符串类型的变量转化为大数
 35      BigNum( const BigNum &);  // 拷贝构造函数
 36      BigNum & operator=( const BigNum &);  // 重载赋值运算符,大数之间进行赋值运算
 37      friend istream&  operator>>(istream&,BigNum&);  // 重载输入运算符
 38      friend ostream&  operator<<(ostream&,BigNum&);  // 重载输出运算符
 39 
 40     BigNum  operator+( const BigNum &) const;   // 重载加法运算符,两个大数之间的相加运算
 41      BigNum  operator-( const BigNum &) const;   // 重载减法运算符,两个大数之间的相减运算
 42      BigNum  operator-( const  int &) const;
 43     BigNum  operator*( const BigNum &) const;   // 重载乘法运算符,两个大数之间的相乘运算
 44      BigNum  operator/( const  int &) const;      // 重载除法运算符,大数对一个整数进行相除运算
 45 
 46     BigNum  operator^( const  int &) const;      // 大数的n次方运算
 47       int  operator%( const  int &) const;         // 大数对一个int类型的变量进行取模运算
 48       bool  operator>( const BigNum &T) const;    // 大数和另一个大数的大小比较
 49       bool  operator>( const  int &t) const;       // 大数和一个int类型的变量的大小比较
 50 
 51      void print();         // 输出大数
 52  };
 53 BigNum::BigNum( const  int b)    // 将一个int类型的变量转化为大数
 54  {
 55      int c,d=b;
 56     len= 0;
 57     memset(a, 0, sizeof(a));
 58      while(d>MAXN)
 59     {
 60         c=d-(d/(MAXN+ 1))*(MAXN+ 1);
 61         d=d/(MAXN+ 1);
 62         a[len++]=c;
 63     }
 64     a[len++]=d;
 65 }
 66 BigNum::BigNum( const  char *s)   // 将一个字符串类型的变量转化为大数
 67  {
 68      int t,k,index,L,i;
 69     memset(a, 0, sizeof(a));
 70     L=strlen(s);
 71     len=L/DLEN;
 72      if(L%DLEN)len++;
 73     index= 0;
 74      for(i=L- 1;i>= 0;i-=DLEN)
 75     {
 76         t= 0;
 77         k=i-DLEN+ 1;
 78          if(k< 0)k= 0;
 79          for( int j=k;j<=i;j++)
 80             t=t* 10+s[j]- ' 0 ';
 81         a[index++]=t;
 82     }
 83 }
 84 BigNum::BigNum( const BigNum &T):len(T.len)   // 拷贝构造函数
 85  {
 86      int i;
 87     memset(a, 0, sizeof(a));
 88      for(i= 0;i<len;i++)
 89         a[i]=T.a[i];
 90 }
 91 BigNum & BigNum:: operator=( const BigNum &n)   // 重载赋值运算符,大数之间赋值运算
 92  {
 93      int i;
 94     len=n.len;
 95     memset(a, 0, sizeof(a));
 96      for(i= 0;i<len;i++)
 97         a[i]=n.a[i];
 98      return * this;
 99 }
100 istream&  operator>>(istream & in,BigNum &b)
101 {
102      char ch[MAXSIZE* 4];
103      int i=- 1;
104      in>>ch;
105      int L=strlen(ch);
106      int count= 0,sum= 0;
107      for(i=L- 1;i>= 0;)
108     {
109         sum= 0;
110          int t= 1;
111          for( int j= 0;j< 4&&i>= 0;j++,i--,t*= 10)
112         {
113             sum+=(ch[i]- ' 0 ')*t;
114         }
115         b.a[count]=sum;
116         count++;
117     }
118     b.len=count++;
119      return  in;
120 }
121 ostream&  operator<<(ostream&  out,BigNum& b)   // 重载输出运算符
122  {
123      int i;
124     cout<<b.a[b.len- 1];
125      for(i=b.len- 2;i>= 0;i--)
126     {
127         printf( " %04d ",b.a[i]);
128     }
129      return  out;
130 }
131 BigNum BigNum:: operator+( const BigNum &T) const    // 两个大数之间的相加运算
132  {
133     BigNum t(* this);
134      int i,big;
135     big=T.len>len?T.len:len;
136      for(i= 0;i<big;i++)
137     {
138         t.a[i]+=T.a[i];
139          if(t.a[i]>MAXN)
140         {
141             t.a[i+ 1]++;
142             t.a[i]-=MAXN+ 1;
143         }
144     }
145      if(t.a[big]!= 0)
146        t.len=big+ 1;
147      else t.len=big;
148      return t;
149 }
150  // BigNum BigNum::operator-(const BigNum&) const
151 
152 BigNum BigNum:: operator-( const BigNum &T) const   // 两个大数之间的相减运算
153  {
154      int i,j,big;
155      bool flag;
156     BigNum t1,t2;
157      if(* this>T)
158     {
159         t1=* this;
160         t2=T;
161         flag= 0;
162     }
163      else
164     {
165         t1=T;
166         t2=* this;
167         flag= 1;
168     }
169     big=t1.len;
170      for(i= 0;i<big;i++)
171     {
172          if(t1.a[i]<t2.a[i])
173         {
174             j=i+ 1;
175              while(t1.a[j]== 0)
176                 j++;
177             t1.a[j--]--;
178              while(j>i)
179                 t1.a[j--]+=MAXN;
180             t1.a[i]+=MAXN+ 1-t2.a[i];
181         }
182          else t1.a[i]-=t2.a[i];
183     }
184     t1.len=big;
185      while(t1.a[len- 1]== 0 && t1.len> 1)
186     {
187         t1.len--;
188         big--;
189     }
190      if(flag)
191         t1.a[big- 1]= 0-t1.a[big- 1];
192      return t1;
193 }
194 
195 BigNum BigNum:: operator-( const  int &b) const   // 大数-int
196  {
197     BigNum B(b);
198      return * this - B;
199 }
200 
201 BigNum BigNum:: operator*( const BigNum &T) const   // 两个大数之间的相乘
202  {
203     BigNum ret;
204      int i,j,up;
205      int temp,temp1;
206      for(i= 0;i<len;i++)
207     {
208         up= 0;
209          for(j= 0;j<T.len;j++)
210         {
211             temp=a[i]*T.a[j]+ret.a[i+j]+up;
212              if(temp>MAXN)
213             {
214                 temp1=temp-temp/(MAXN+ 1)*(MAXN+ 1);
215                 up=temp/(MAXN+ 1);
216                 ret.a[i+j]=temp1;
217             }
218              else
219             {
220                 up= 0;
221                 ret.a[i+j]=temp;
222             }
223         }
224          if(up!= 0)
225            ret.a[i+j]=up;
226     }
227     ret.len=i+j;
228      while(ret.a[ret.len- 1]== 0 && ret.len> 1)ret.len--;
229      return ret;
230 }
231 BigNum BigNum:: operator/( const  int &b) const   // 大数对一个整数进行相除运算
232  {
233     BigNum ret;
234      int i,down= 0;
235      for(i=len- 1;i>= 0;i--)
236     {
237         ret.a[i]=(a[i]+down*(MAXN+ 1))/b;
238         down=a[i]+down*(MAXN+ 1)-ret.a[i]*b;
239     }
240     ret.len=len;
241      while(ret.a[ret.len- 1]== 0 && ret.len> 1)
242         ret.len--;
243      return ret;
244 }
245  int BigNum:: operator%( const  int &b) const    // 大数对一个 int类型的变量进行取模
246  {
247      int i,d= 0;
248      for(i=len- 1;i>= 0;i--)
249         d=((d*(MAXN+ 1))%b+a[i])%b;
250      return d;
251 }
252 BigNum BigNum:: operator^( const  int &n) const   // 大数的n次方运算
253  {
254     BigNum t,ret( 1);
255      int i;
256      if(n< 0)exit(- 1);
257      if(n== 0) return  1;
258      if(n== 1) return * this;
259      int m=n;
260      while(m> 1)
261     {
262         t=* this;
263          for(i= 1;(i<< 1)<=m;i<<= 1)
264            t=t*t;
265         m-=i;
266         ret=ret*t;
267          if(m== 1)ret=ret*(* this);
268     }
269      return ret;
270 }
271  bool BigNum:: operator>( const BigNum &T) const     // 大数和另一个大数的大小比较
272  {
273      int ln;
274      if(len>T.len) return  true;
275      else  if(len==T.len)
276     {
277         ln=len- 1;
278          while(a[ln]==T.a[ln]&&ln>= 0)
279           ln--;
280          if(ln>= 0 && a[ln]>T.a[ln])
281             return  true;
282          else
283             return  false;
284     }
285      else
286         return  false;
287 }
288  bool BigNum:: operator>( const  int &t) const   // 大数和一个int类型的变量的大小比较
289  {
290     BigNum b(t);
291      return * this>b;
292 }
293  void BigNum::print()    // 输出大数
294  {
295      int i;
296     printf( " %d ",a[len- 1]);
297      for(i=len- 2;i>= 0;i--)
298       printf( " %04d ",a[i]);
299     printf( " \n ");
300 }
301  bool ONE(BigNum a)
302 {
303      if(a.len ==  1 && a.a[ 0] ==  1) return  true;
304      else  return  false;
305 }
306 
307 BigNum A,B,X,Y;
308  int a[ 1010], b[ 1010], x[ 1010], y[ 1010], c[ 1010], d[ 1010];
309 
310  int main()
311 {
312      int t, n;
313     scanf( " %d ",&t);
314      for( int cas= 1; cas<=t; ++cas)
315     {
316         scanf( " %d ",&n);
317         cin >> A >> X >> B >> Y;
318         A = A -  1;
319         B = B -  1;
320         X = X -  1;
321         Y = Y -  1;
322          for( int i= 0; i<n; i++)
323         {
324              if(A.a[ 0]% 2== 0) a[i] =  0;
325              else a[i] =  1;
326              if(B.a[ 0]% 2== 0) b[i] =  0;
327              else b[i] =  1;
328              if(X.a[ 0]% 2== 0) x[i] =  0;
329              else x[i] =  1;
330              if(Y.a[ 0]% 2== 0) y[i] =  0;
331              else y[i] =  1;
332 
333             A = A /  2;
334             B = B /  2;
335             X = X /  2;
336             Y = Y /  2;
337         }
338          int flag1 =  0;
339          for( int i= 0; i<n; i++)
340         {
341              int flag2 =  0;
342              for( int j= 0; j<n; j++)
343             {
344                 c[j] = x[(j+i)%n] ^ a[j];
345                 d[j] = y[(j+i)%n] ^ b[j];
346                  if(c[j]!=d[j])
347                 {
348                     flag2 =  1;
349                      break;
350                 }
351             }
352              if(flag2== 0) {flag1 =  1break;}
353         }
354          if(flag1== 1) printf( " Case %d: Yes\n ",cas);
355          else  if(flag1== 0) printf( " Case %d: No\n ",cas);
356 
357     }
358      return  0;
359 }
View Code

 

转载于:https://www.cnblogs.com/byluoluo/p/3571919.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值