• 蒟蒻的 线性基 刷题记录


    HDU3949 XOR

    • 大意:给出n个数,求这些数通过xor能得到的第k小的值
    • 做法:先高斯消元,完了之后回代,然后第k小,k用二进制表示,是1的那位就选,是0 的就不选
    • 注意:给出的n个数能不能xor出0?因为题目是不允许不选,所以要考虑0的情况。
    • 代码:
      #include <bits/stdc++.h>
      #define nmax 10010
      
      using namespace std;
      typedef long long ll;
      ll a[nmax],b[70],k[70]; //k[i] 第i小的数
      int n,q;
      
      int main(){
          int T;
          cin>>T;
          for (int cas=1; cas<=T; cas++) {
              memset(b,0,sizeof(b));
              memset(k,0,sizeof(k));
              printf("Case #%d:
      ",cas);
              scanf("%d",&n);
              for (int i=0; i<n; i++) {
                  scanf("%lld",&a[i]);
                  //求线性基
                  for (int j=61; j>=0; j--) {
                      if(a[i]&(1LL<<j)){
                          if(b[j]) a[i]^=b[j];
                          else { b[j]=a[i]; break; }
                      }
                  }
              }
              //往上回代,顺便统计个数
              int cnt=0;
              for (int i=0; i<=61; i++) if(b[i]) {
                      k[cnt]=b[i];
                      cnt++;
                      for (int j=i+1; j<=61; j++) if(b[j]&(1LL<<i)) b[j]^=b[i];
              }
              ll mmax=(1LL<<cnt)-1;
              scanf("%d",&q);
              //cout<<"q= "<<q<<endl;
              ll inq;
              bool flag=false;//特别判断0
              if(cnt<n) flag=true;
              for (int j=0; j<q; j++) {
                     // cout<<"quq"<<endl;
                  scanf("%lld",&inq);
                  if(flag) inq--;  //也是判断0的内容
                  if(inq>mmax) cout<<-1<<endl;
                  else {
                      ll ans=0;
                      for (int i=0; (1LL<<i)<=inq; i++) if((1LL<<i)&inq) ans^=k[i];
                      printf("%lld
      ",ans);
                  }
              }
          }
          return 0;
      }

      BZOJ2460 元素

    • 做法:贪心,按magic值从大到小排序求线性基
    • 代码:
      #include <bits/stdc++.h>
      #define nmax 1010
      
      using namespace std;
      typedef long long ll;
      struct stone{
          ll num,mac;
          bool operator < (const stone a) const { return a.mac<mac; }
      }st[nmax];
      int n;
      ll b[70]={0};
      
      int main(){
          cin>>n;
          for (int i=0; i<n; i++) scanf("%lld%lld",&st[i].num,&st[i].mac);
          sort(st,st+n);
          //for (int i=0; i<n; i++) cout<<st[i].num<<' '<<st[i].mac<<endl;
          ll ans=0;
          for (int i=0; i<n; i++) for (int j=63; j>=0; j--) if(st[i].num&(1LL<<j)){
              if(b[j]) st[i].num^=b[j];
              else{
                  b[j]=st[i].num;
                  ans+=st[i].mac;
                  break;
              }
          }
          printf("%lld
      ",ans);
          return 0;
      }

     BZOJ2115 XOR

    • 做法:dfs先把图拉成一棵树,然后看有没有倒回去的边(类似tarjan那种)处理出所有的环的xor值,然后和1~ndfs树上那个值做线性基求出ans
    • 注意:wa的地方有两点,一个是处理环的时候,是不是环要看是不是dfs中“指回去”,用一个数组记录dfs的顺序。另一个是求最大xor值时。1~n那条路不要加到线性基里去,因为那个数是必须要取的,加到线性基里后面求最大值的时候可能就不取它了。
    • 代码:
       1 #include <bits/stdc++.h>
       2 #define nmax 50010
       3 #define mmax 100010
       4 
       5 using namespace std;
       6 typedef long long ll;
       7 int head[nmax]={0},d[nmax]={0};  //被vis到的顺序
       8 ll a[nmax+mmax],tmp[nmax],b[70]={0};
       9 int n,m,idx=0,idxa=0;  //idza是记录环的数量
      10 struct edge{
      11     int v,ne;
      12     ll w;
      13 }e[mmax*2];
      14 
      15 inline void addedge(int u,int v,ll w){
      16     idx++;
      17     e[idx].v=v;
      18     e[idx].w=w;
      19     e[idx].ne=head[u];
      20     head[u]=idx;
      21 }
      22 
      23 void build(){
      24     cin>>n>>m;
      25     int a,b;   ll c;
      26     for (int i=0; i<m; i++) {
      27         scanf("%d%d%lld",&a,&b,&c);
      28         addedge(a,b,c);
      29         addedge(b,a,c);
      30     }
      31 }
      32 
      33 void dfs(int u,int cnt){
      34     d[u]=cnt;
      35     for (int i=head[u]; i; i=e[i].ne){
      36         int v=e[i].v;  ll w=e[i].w;
      37         if(d[v]>d[u]) continue;
      38         if(d[v]){
      39             ll x=tmp[v]^tmp[u]^w;  //这个环的xor值
      40             if(x) a[++idxa]=x;  //如果是0就舍弃
      41         }else {
      42             tmp[v]=tmp[u]^w;  //在dfs(u)之前,u的tmp值已经算出
      43             dfs(v,cnt+1);
      44         }
      45     }
      46 }
      47 
      48 void xxj(){
      49     for (int i=1; i<=idxa; i++) for (int j=63; j>=0; j--) if((1LL<<j)&a[i]){
      50         if(b[j]) a[i]^=b[j];
      51         else { b[j]=a[i]; break; }
      52     }
      53     ll ans=tmp[n];
      54     for (int i=63; i>=0; i--) ans=max(ans,ans^b[i]);
      55     printf("%lld
      ",ans);
      56 }
      57 
      58 int main(){
      59     build();
      60     dfs(1,1);
      61     xxj();
      62     return 0;
      63 }

     

    BZOJ2844: albus就是要第一个出场

    • 对于给定的大小为N数列a,它的子集有2^n个,每个子集可以异或的所有的数可以用线性基表示
    • 设线性基有b个,然后不在线性基里的数有x=n-b个
    • 可以知道通过a任意异或出的所有数是这样一个情况:一共有2^b个不同的数,每个数出现的次数相同为2^x
    • 证明:把a分成两份,线性基的一份和不在线性基的一份,然后在不在线性基的那一份里随便取一种排列并把它们异或,设结果为v,v用线性基那一份也可以造出来,然后v^v=0,然后再用线性基造一遍所有的数,这些数就又全部出现了一次,这样搞可以让这些数全部出现2^x次
    • 代码:
      #include <bits/stdc++.h>
      #define nmax 100010
      #define mod 10086
       
      using namespace std;
      typedef long long ll;
      ll a[nmax],b[60];
      ll n,x;
       
      ll fastpow(ll x){
          ll ta=2,ans=1;
          for (ll i=1; i<=x; i<<=1){
              if(x&i) ans=(ans*ta)%mod;
              ta=(ta*ta)%mod;
          }
          return ans;
      }
       
      int main(){
          scanf("%lld",&n);
          for (ll i=0; i<n; i++) {
              scanf("%lld",&a[i]);
              for (ll j=40; j>=0; j--){
                  if( (1LL<<j)&a[i] )
                      if(b[j]) a[i]^=b[j];
                      else { b[j]=a[i]; break; }
              }
          }
          scanf("%lld",&x);
          int k=0,cnt=0;
          for (ll i=0; i<=40; i++) {
              if(b[i]) {
            if( x & (1<<i) ) k+=(1LL<<cnt);//注意这里加的不是b[i]。。
                  cnt++;
              }
          }
          cout<<k*fastpow(n-cnt)%mod+1<<endl;
          return 0;
      }    
  • 相关阅读:
    使用正则表达式,取得点击次数,函数抽离
    爬取校园新闻首页的新闻
    网络爬虫基础练习
    Hadoop大作业
    Hive基本操作与应用
    熟悉HBase基本操作
    爬虫大作业
    熟悉常用的HDFS操作
    数据结构化与保存
    使用正则表达式,取得点击次数,函数抽离
  • 原文地址:https://www.cnblogs.com/jiecaoer/p/11249614.html
Copyright © 2020-2023  润新知