• 洛谷P4135 作诗 --分块基础


    作为我分块入门的第一道题

    这道题花了我一整天的时间才搞出来

    整理一下分块很实用思路:

    分块的主要思路:比如操作区间[l,r]

    1.如果l,r在一个分块里或者相邻的分块里,直接暴力

    2. 否则,边角块暴力+中间分块整体解决

    总体时间复杂度是n√n  能承受的数据范围是100000以内, 可以说很大了

    想思路的难点就在于如何预处理,讲几个常用的预处理办法:

    1. F[i][j] 数组存从[i,j]的答案

    2. G[i][j] 数组存的j 在块 i 里面的特征, 可以用前缀和表示

    有些预处理比较有难度,比如这一题的F[i][j],要点是:不要重复劳动,不要重复走一个区域

    一遍就把所有该求的东西求出来

    讲几个点吧:

    1. 能不用Map就不用Map ,map虽然是stl里面的很方便,但是使用一次就是logn的时间,对时间要求紧的题目就不要用了

    2. 分块的几个公式不要写错

    1 int n, S, N;
    2 int A[maxn], ID[maxn];
    3 
    4 S = sqrt(n);//初始化
    5 N = (n-1)/S + 1;
    6 for(int i = 1;i <= n;i++) {
    7     scanf("%d",&A[i]);
    8     ID[i] = (i-1)/S + 1;
    9 }

    3.O(1)初始化的技巧要会,用一个次数t来代表第几次使用cnt数组,然后把次数更新在cntM数组里面

    1 if(cntM[A[i]] != t) {
    2     cntM[A[i]] = t;
    3     cnt[A[i]] = 0;
    4 }

    4.如果可以的话,快速读入也是很重要的 

    5. 在处理边角块的时候, for循环的使用技巧也很重要,比如跨区域扫描。

    1     for(int i = x;i <= y;) {    
    2     
    3       if(i == ID[x]*S) i = (ID[y]-1)*S+1;
    4         else i++; 
    5     }

    6. 还有交换x,y变量的骚技巧:

    1 x^=y^=x^=y;

    完整代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<map>
      4 #include<cmath>
      5 #include<iostream>
      6 using namespace std;
      7 const int maxn = 100010;
      8 const int maxm = 333;
      9 
     10 int n, m, c, S, N;
     11 int A[maxn], ID[maxn], cnt[maxn], Q[maxn], cntM[maxn];
     12 int F[maxm][maxm], G[maxm][maxn];
     13 
     14 inline int query(int x,int y,int t) {
     15     int ret = 0;
     16     
     17     if(ID[x] + 1 >= ID[y] ) {
     18         for(int i = x;i <= y;i++) {
     19             if(cntM[A[i]] != t) {
     20                 cntM[A[i]] = t;
     21                 cnt[A[i]] = 0;
     22             }
     23             cnt[A[i]]++;
     24             if(cnt[A[i]]%2 == 0 && cnt[A[i]] >= 2) ret++;
     25             else if(cnt[A[i]]%2 == 1 && cnt[A[i]] >= 2) ret--;
     26         }
     27         return ret;
     28     }
     29     
     30     ret = F[ID[x]+1][ID[y]-1];
     31     
     32     
     33     for(int i = x;i <= y;) {    
     34         if(cntM[A[i]] != t) {
     35                 cntM[A[i]] = t;
     36                 cnt[A[i]] = 0;
     37         }
     38         cnt[A[i]]++;
     39         
     40         int tp = G[ID[y]-1][A[i]] - G[ID[x]][A[i]];
     41         int sum = tp + cnt[A[i]];
     42         
     43         if(sum <= 1) {
     44             if(i == ID[x]*S) i = (ID[y]-1)*S+1;
     45             else i++;
     46             continue;
     47         }
     48         
     49         if(sum%2 == 1) ret--;
     50       if(sum%2 == 0) ret++;
     51     
     52       if(i == ID[x]*S) i = (ID[y]-1)*S+1;
     53         else i++; 
     54     }
     55     return ret;
     56 }
     57 
     58 int main() {
     59     //freopen("d.txt","r",stdin);
     60     scanf("%d %d %d",&n,&c,&m);
     61     S = sqrt(n);
     62     N = (n-1)/S + 1;
     63     for(int i = 1;i <= n;i++) {
     64         scanf("%d",&A[i]);
     65         ID[i] = (i-1)/S + 1;
     66     }
     67     
     68     int sum = 0;
     69     for(int i = 1;i <= N;i++) {
     70         sum = 0;
     71         int t = i;
     72         for(int j = (i-1)*S + 1;j <= n;j++) {
     73             int p = ID[j];
     74             if(cntM[A[j]] != t) {
     75                 cntM[A[j]] = t;
     76                 cnt[A[j]] = 0;
     77             }
     78             cnt[A[j]]++;
     79             if(cnt[A[j]]%2 == 0 && cnt[A[j]] >= 2) sum++;
     80             else if(cnt[A[j]]%2 == 1 && cnt[A[j]] >= 2) sum--;
     81             if(j%S == 0 || j == n) F[i][p] = sum;
     82         }
     83     }
     84   
     85   memset(cnt,0,sizeof(cnt));
     86   for(int i = 1;i <= n;i++) {
     87       cnt[A[i]]++;
     88       if(i%S == 0 || i == n) {
     89           for(int j = 1;j <= c;j++) G[ID[i]][j] = cnt[j]; 
     90         }
     91     }
     92     
     93   int ans = 0;
     94     for(int i = 1,x,y;i <= m;i++) {
     95       scanf("%d %d",&x,&y);
     96       x=(x+ans)%n+1;
     97     y=(y+ans)%n+1;
     98     if(x>y) x^=y^=x^=y;
     99    // cout<<x<<" : "<<y<<endl;
    100       ans = query(x,y,i+N);
    101         printf("%d
    ",ans);
    102     }
    103 
    104     return 0;
    105 } 
  • 相关阅读:
    LinkLabel控件使用
    读取mysql代码片段
    设置点风格
    C# List 用法
    图片焦点图切换效果
    dreamweaver 泛泛之谈
    js 之for..in、表单及事件触发
    实现省份查询 功能
    input类主要是
    js (1)
  • 原文地址:https://www.cnblogs.com/frankscode/p/9511886.html
Copyright © 2020-2023  润新知