Codeforces 341

D:

二维矩阵区间xor上一个数询问区间xor和。

嘛,如果不是xor应该是没法做的吧。因为是xor,所以我们只需要考虑修改的区间的数有多少个,是奇数个还是偶数个之类的就行了,因为xor两次等于不xor嘛,所以对行列的奇偶用树状数组维护就行了。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 #define lb(x) ((x)&(-(x)))
 8 
 9 const int maxn=1010;
10 
11 int n,m,z[2][2][maxn][maxn];
12 
13 void modify(int x,int y,long long v)
14 {
15     for (int a=x;a<=n;a+=lb(a))
16         for (int b=y;b<=n;b+=lb(b))
17             z[x&1][y&1][a][b]^=v;
18 }
19 
20 long long query(int x,int y)
21 {
22     long long ans=0;
23     for (int a=x;a;a-=lb(a))
24         for (int b=y;b;b-=lb(b))
25             ans^=z[x&1][y&1][a][b];
26     return ans;
27 }
28 
29 int main()
30 {
31     scanf("%d%d",&n,&m);
32     for (int a=1;a<=m;a++)
33     {
34         int opt,x1,y1,x2,y2;
35         scanf("%d%d%d%d%d",&opt,&x1,&y1,&x2,&y2);
36         if (opt==1) printf("%I64d
",query(x1-1,y1-1)^query(x2,y1-1)^query(x1-1,y2)^query(x2,y2));
37         else
38         {
39             long long v;
40             scanf("%I64d",&v);
41             modify(x1,y1,v);
42             modify(x2+1,y1,v);
43             modify(x1,y2+1,v);
44             modify(x2+1,y2+1,v);
45         }
46     }
47     return 0;
48 }
View Code

 

E:

N个数,每次选择两个,把大的那个减去小的那个然后把小的那个翻倍。构造任意一种操作序列,使得最后序列中恰好有两个数不为0。

这题神爆了。

一开始呢我天真的认为对任意两个数不断乱搞总是可行的,但是轻轻松松就发现了4 8这种反例。

然后HZC说三个数,就又去搞搞。我把这三个数两两拿来不断乱搞,我以为任意三个数中总有两个乱搞是可行的,但是又发现了6 8 32这种反例(记不清是不是这个了,反正有反例)。

然后就蛋疼掉了。然后中间在找反例的时候我有个做法是把数不断random_shuffle希望反例被搞掉,从这里面想到定一个序会不会更好。还是基于HZC给出的神一般的思路从三个数入手,考虑三个数v1、v2、v3,并且有v1<=v2<=v3。有了三个定了序的数也不知道干什么,随便画了几组例子,发现如果设v4=floor(v2/v1)的话,那么如果v4=2^x-1,那么不断让v1 v2进行的操作对于v2来讲就相当于v2=v2 mod v1。但是v4大部分情况下是不会那么好的,但注意到我们有v3,一个比v2更大的数,我们把v4二进制分解。从低位往高位走,如果当前位为0,就让v1和v3操作,否则让v1和v2操作。如果操作顺利的话,那么我们最后是将v2变成了v2 mod v1了,因为v4,也就是floor(v2/v1)的每一位都变成0了。但是需要满足一个条件:在这个过程中始终有v1<=v2且v1<=v3。第一个很显然,因为我v4都还没被减为0,关键是第二个。其实证明起来也不难,考虑一种极限情况v4=2^x,这样也好说一点。这种时候前面都是一直是v3在被减,这样对v3的影响最大。但是就算这些位全部减了,所产生的影响也是一定小于v4*v1的,因为这是二进制。但是v4=floor(v2/v1),而又有v3>=v2>=v1*v4>影响,所以这个过程中一直都有v3>=v1,所以我们一定能够使v2变为v2 mod v1。那么我们操作完后会得到新的三个数v1'<=v2'<=v3',并且由于v1'=v2 mod v1,所以一定有v1'<v1,所以我们每次一定能够使最小的那个数变小,最终达到0!所以任意三个非零数都可以通过一定的操作变为两个非零数加上一个零,所以,over。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<cctype>
  5 #include<algorithm>
  6 
  7 using namespace std;
  8 
  9 const int BUF_SIZE = 30;
 10 char buf[BUF_SIZE], *buf_s = buf, *buf_t = buf + 1;
 11   
 12 #define PTR_NEXT() 
 13     { 
 14         buf_s ++; 
 15         if (buf_s == buf_t) 
 16         { 
 17             buf_s = buf; 
 18             buf_t = buf + fread(buf, 1, BUF_SIZE, stdin); 
 19         } 
 20     }
 21    
 22 #define readint(_n_) 
 23     { 
 24         while (*buf_s != '-' && !isdigit(*buf_s)) 
 25             PTR_NEXT(); 
 26         bool register _nega_ = false; 
 27         if (*buf_s == '-') 
 28         { 
 29             _nega_ = true; 
 30             PTR_NEXT(); 
 31         } 
 32         int register _x_ = 0; 
 33         while (isdigit(*buf_s)) 
 34         { 
 35             _x_ = _x_ * 10 + *buf_s - '0'; 
 36             PTR_NEXT(); 
 37         } 
 38         if (_nega_) 
 39             _x_ = -_x_; 
 40         (_n_) = (_x_); 
 41     }
 42 
 43 #define finish {printf("-1
");return 0;}
 44 
 45 const int maxn=1010;
 46 const int maxs=1000010;
 47 
 48 int n,s,z[maxn],y[maxs][2];
 49 
 50 int check()
 51 {
 52     int cnt=0;
 53     for (int a=1;a<=n;a++)
 54         if (z[a]) cnt++;
 55     return cnt;
 56 }
 57 
 58 int main()
 59 {
 60     readint(n);
 61     for (int a=1;a<=n;a++)
 62         readint(z[a]);
 63     int p1=0,p2=0,p3,x;
 64     for (int a=1;a<=n;a++)
 65     {
 66         if (!z[p1]) p1=a;
 67         else
 68         {
 69             if (!z[p2]) p2=a;
 70             else
 71             {
 72                 p3=a;
 73                 while (true)
 74                 {
 75                     if (z[p3]<z[p1]) swap(p1,p3);
 76                     if (z[p2]<z[p1]) swap(p1,p2);
 77                     if (z[p3]<z[p2]) swap(p2,p3);
 78                     if (!z[p1]) break;
 79                     x=z[p2]/z[p1];
 80                     while (x)
 81                     {
 82                         s++;
 83                         y[s][0]=p1;
 84                         if (x&1) y[s][1]=p2,z[p2]-=z[p1];
 85                         else y[s][1]=p3,z[p3]-=z[p1];
 86                         z[p1]<<=1;
 87                         x>>=1;
 88                     }
 89                 }
 90                 p1=p2;p2=p3;
 91             }
 92         }
 93     }
 94     if (check()!=2) finish;
 95     printf("%d
",s);
 96     for (int a=1;a<=s;a++)
 97         printf("%d %d
",y[a][0],y[a][1]);
 98 
 99     return 0;
100 }
View Code

 

原文地址:https://www.cnblogs.com/zhonghaoxi/p/3293553.html