HDU 6085 Rikka with Candies (暴力压位)

题目链接

HDU 6085 Rikka with Candies

分析

其实很容易想到一个有技巧的暴力方法,我们可以这样办

首先对于每一个 Ai 我们考虑比 Ai 大的部分 B ,对于这部分 B,Ai%B=Ai ,所以我们通过计算前缀和可以在 O(1) 计算出这部分值,因此我们先不考虑这部分值,

对于比 Ai 小的部分 B 我们反过来对每个 Bi 考虑比 Bi 大的部分 A ,那么对于每个 Bi,Ai 的贡献一定是 [0,1,2,Bi1] 的循环,即 A,[Bi,maxAi] 这一部分的贡献恰好是循环 [0,1,2,Bi1] ,如果我们把 Ai 处理成

a[i] : 用01表示值为i的数存在与否,b[i]同理

则对于每个 Bi 我们只需将 a[kBi,(k+1)Bi1] 这一部分加到答案 ans[0,1,2,Bi1] ,暴力是 O(nm) 如果我们将 a 压位就可以在 O(nm/32) 得出结果.具体压位可见代码

AC code

// Problem : 6085 ( Rikka with Candies )     Judge Status : Accepted
// RunId : 21600845    Language : G++    Author : zouzhitao
// Code Render Status : Rendered By HDOJ G++ Code Render Version 0.01 Beta
#include
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define ms(x,v) memset((x),(v),sizeof(x))
#define scint(x)  scanf("%d",&x );
using namespace std;
const int MOD = 1e9+7;
const double eps = 1e-8;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> PII;

const int maxn = 5e4 +10;

LL ans[maxn];
LL bit_ans[maxn];
int a[maxn],b[maxn];
LL digit[maxn][35];
LL sum[maxn];
int maxa,maxb;
void add(int idx,int l){
   //重idx开始+l位到bit_ans;
   int L = 0 , R = min(maxa-idx,l-1);
   while (L<=R) {
      int d = L/32;
      if(idx+L>maxa)break;
      if(R-L>=31){
         bit_ans[d] ^=digit[idx+L][32];
         L+=32;
      }else{
         bit_ans[d] ^=digit[idx+L][R-L+1];
         L=R+1;
      }
      // std::cout << L<<" LR "<// std::cout << bitset<64>(bit_ans[d]) << '\n';
   }
}
int main(int argc, char const *argv[]) {
   int T;
   scanf("%d",&T );
   while (T--) {
      maxa = 0;
      maxb = 0;
      int n,m,k;
      scanf("%d%d%d",&n,&m,&k );
      ms(a,0);ms(b,0);ms(ans,0);
      ms(digit,0);ms(sum,0);
      ms(bit_ans,0);
      for(int i=0 ; iint x;scanf("%d",&x );
         a[x] =1;
         maxa = max(x,maxa);
      }
      for(int i=0 ; iint x;scint(x);
         b[x]=1;
         maxb = max(maxb,x);
      }
      //压位
      for(int i=1 ; i<=maxa ; ++i){
         LL bit =0;
         // std::cout << i<<" " <
         for(int j =0 ; j<32&&(i+j)<=maxa ; ++j){
            bit <<=1;bit |=a[i+j];//从i开始长度为j+1的位
            digit[i][j+1] = bit<<(31-j);
            // std::cout << bitset<64>(digit[i][j+1]) << '\n';
         }
      }
      for(int i=1 ; i<=maxb ; ++i){
         if(b[i]){
            // std::cout << i<<" bi "<
            for(int j=i ; j<=maxa ;j+=i ){
               add(j,i);
            }
         }
      }
      for(int i=0 ; i*32 <=5e4 ; ++i){
         int j = (i+1) * 32 -1;
         int t =32;
         while (t--) {
            ans[j] = bit_ans[i]&1;j--;bit_ans[i]>>=1;
         }
      }
      sum[0] =0;
      for(int i=1 ; i<=maxb ; ++i){
         sum[i] = sum[i-1] + b[i];
      }
      for(int i=1 ; i<=maxa ; ++i){
         if(a[i]){
            ans[i]^= (sum[maxb]-sum[i])&1;
         }
      }
      while (k--) {
         int x;scint(x);
         printf("%d\n",ans[x] );
      }
   }
   return 0;
}

你可能感兴趣的:(算法刷题)