一些趣题的回忆

  这种题目,常常道听途说,或是考试用题。常常难觅出处,却又非常经典。故选其精华,小列如下。



T1:fleet 给定一个序列,询问[L,R]间有多少种不同的权值。

e.g.:序列1,1,2,3,2的[1,5]有3种不同权值,[1,3]有2种不同权值。

ANSWER:可以考虑使用主席树求解。查询[L,R]时返回root[R]的[L,R]值之和。root[i]与root[i-1]的不同在于:prev[aa[i]]这个位置(即上一次出现aa[i]的位置)-1,在i这个位置+1。先预处理完毕,再应付查询。



T2:给定一个序列,询问[L,R]间有多少种权值k恰出现k次。

e.g.:序列1,1,2,3,2的[1,1]有1种权值,[1,2]有0种权值,[2,5]有2种权值。

ANSWER:可以考虑使用主席树求解。但是,我们也可以考虑使用离线。因为答案本质上统计的是一种情形,而我们可以考虑该情形对答案的贡献。如果把询问[L,R]转化为二维矩阵中某点[L,R]的权值,那么每一种情形的贡献也可以看做是矩形的修改。因为这样很令人不爽,可以进一步地转换,使用差分的思想,将矩形拆成4个角,问题于是转化为单点修改与矩阵前缀和的查询。这个东西很像BZOJ的一道题:MONICA。那是一道CDQ分治套树状数组的典型题目,因为有时间的先后。但是,这道题目完全可以先修改再查询,于是可以sort以后直接使用树状数组求解。

 1 #define PN "count"
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 template<class T>inline void readint(T &res) {
 6     static char ch;T flag=1;
 7     while((ch=getchar())<‘0‘||ch>‘9‘)if(ch==‘-‘)flag=-1;
 8     res=ch-48;
 9     while((ch=getchar())>=‘0‘&&ch<=‘9‘)res=res*10+ch-48;
10     res*=flag;
11 }
12 const int N = 1000000 + 100;
13 const int Q = 1000000 + 100;
14 struct DATUM {
15     int x, y, delta;
16     bool operator<(const DATUM &rhs) const {
17         if(x!=rhs.x) return x<rhs.x;
18         if(y!=rhs.y) return y<rhs.y;
19         if(delta!=rhs.delta) return delta<rhs.delta;
20     }
21 } data[N*4+Q];
22 int tot, ans[Q];
23 inline void addD(int x,int y,int delta) {data[++tot]=(DATUM){x,y,delta};}
24
25 int n, a[N];
26 void add(int pos,int val) {for(int x=pos;x<=n;x+=x&-x)a[x]+=val;}
27 int query(int pos) {int val=0;for(int x=pos;x;x-=x&-x)val+=a[x];return val;}
28
29 #include <vector>
30 std::vector<int> same[N];
31 int main() {
32     int q;readint(n);readint(q);
33     for( int i = 1; i <= n; i++ ) same[i].push_back(0);
34     for( int i = 1, x, siz; i <= n; i++ ) {
35         readint(x);same[x].push_back(i);
36         siz=same[x].size();
37         if(siz>x) {
38             addD(same[x][siz-x-1]+1,i,+1);
39             addD(same[x][siz-x]+1,i,-1);
40             if(siz>x+1) addD(same[x][siz-x-2]+1,i,-1);
41             if(siz>x+1) addD(same[x][siz-x-1]+1,i,+1);
42         }
43     }
44     for( int i = 1, l, r; i <= q; i++ ) readint(l),readint(r),addD(l,r,i+1);
45     std::sort(data+1,data+tot+1);
46     for( int i = 1; i <= tot; i++ ) {
47         if(data[i].delta<=1) add(data[i].y,data[i].delta);
48         else if(data[i].y>=1&&data[i].y<=n) ans[data[i].delta-1]=query(data[i].y);
49     }
50     for( int i = 1; i <= q; i++ ) printf("%d\n",ans[i]);
51     return 0;
52 }


未完待续……

时间: 2024-11-05 20:36:09

一些趣题的回忆的相关文章

序列相关的趣题 之四

(8) 给定一个英文单词,消除其中重复的字母,只能删掉字母,不能交换字母顺序,最后原单词中每个字母只出现一次,求字典序最小的结果. 这是toj一个题,百度面试也问过,原题见 http://acm.tju.edu.cn/toj/showp3257.html 此题我非常喜欢,巧妙之处是其算法是O(n)的-- .我们一个字母一个字母加入序列,一旦来了一个比较"小"的字母,因为我们需要字典顺序最小,我们希望它尽可能靠前.所以我们试图"冒泡"似的把小的往前面送,经过尾部那些较

序列相关的趣题 之二

(4)数组中找到两个数和的绝对值最小 像不像2-SUM? 不多解释,主要是绝对值大的动就行,两头扫的方法真好!当然要先排序,出去排序就是O(n),算上排序的话退化到O(nlogn) 这也是codility上的问题,还没来得及整理. 上个代码: // you can also use includes, for example: // #include <algorithm> #include <algorithm> int ab(int x) { return (x >= 0

uyhip 趣题 拉灯问题总有解吗?

这是一个让我纠结许久,又不甘放弃的puzzle.在一个意志力极度薄弱的下午,对不起,我看了答案...所以,这又是一篇马后炮文章.但不是所有马后炮都一文不值.如果在讲解一个解答的时候,我们不能把思考背后的动机讲清楚,于他人和自己的价值就会小很多.每一步推理的过程,每一个构造的细节,不是无迹可寻的.我希望去揭示背后的东西. 一个解答背后包含了大量的探索.解谜高手对于如何避免无效的思考,摸清靠谱的思路,总是有一套自己的办法.遗憾的是,好些同学由于各种原因,没有公开自己的方法.例如,高斯同学,他认为数学

智力趣题几则

古时一位农民被人诬陷,农民据理力争,县官因已经接受别人的贿赂,不肯放人,又找不到理由,就出了个坏主意.叫人拿来十张纸条,对农民说:“这里有十张纸条,其中有九张写的‘死’, 一张写的‘生’,你摸一张,如果是‘生’,立即放你回去,如果是‘死’,就怪你命不好,怨不得别人.”聪明的农民早已猜到纸条上写的都是“死”,无论抓哪一张都一样.于是他想了个巧妙的办法,结果死里逃生了.你知道他想的什么办法吗? 把其中的一张纸条吃下去,再根据排除法,结果就有九张死那么它吃下去的就是“生” 称苹果         有十

趣题[0]

趣题[0] 来源 17级老学长的作业题 题面 \(n\) 个物品,有两种值\(a[i]\)和\(b[i]\),给定\(k\).从中选出一些物品,使得 \(\sum{a[i]} = k * \sum{b[i]}\),并且 \(\sum{a[i]}\) 尽量大,求满足条件的最大的 \(\sum{a[i]}\). \(1 <= n.a[i].b[i] <= 100\) \(1 <= k <= 10\) 题解 做差值之后分正负做背包,然后扫一遍即可. 复杂度 \(O(100 * k * n

趣题[1]

趣题[1] 来源 http://www.csie.ntnu.edu.tw/~u91029/Sequence3.html UVA - 12192 介绍 引入 \(n*m\)的矩阵,每行从左到右递增,每列从上到下递增,在矩阵中找数\(x\)出现过的位置. 具体做法可以在这个链接ctrl+F[Search in Sorted Matrix: Saddleback Search],复杂度\(O(n+m)\) 想法 现在我们知道了,从这样的矩阵的右上角走下来可以把矩阵分成两个部分,左上部分小于\(x\),

算法趣题之回文数

题目:求用十进制.二进制.八进制表示都是回文数的所有数字中,大于十进制数10的最小值. 啥叫回文数:如果把某个十进制数按相反的顺序排列,得到的数和原来的数相同,则这个数就是"回文数".例如12321就是一个回文数. 这个题目拿Ruby.JavaScript.python.Java都很容易实现,因为这些语言都提供了字符串逆序处理的接口,或者相关其他接口,而C语言没有提供直接转换的接口,所以下面用C语言解题,其中设计的封装在工作中也会经常碰到,故记录并分享,如有错误或者有更好的算法,欢迎留

趣题——“1”的个数

题目:编写一个函数,确定一个整数的计算机内部表示中有多少个"1". 方法一: 思路: 这个问题看上去是一个简单的转换题,即将一个十进制转换为二进制.但事实上,任何一个数字在计算机中已经是二进制表示了.因此,不再需要显式地使用程序将其转换.对于一个二进制,有多少个1,可以从低位开始数.即每次右移一位,并判断移除的这一位是否为1,直到右移结果为0为止. 例如: 在100101 中, 1. 将其与000001 做与运算,得到最后一位,为1; 2. 右移一位,得到10010; 3. 重复步骤1

序列相关的趣题 之中的一个

闲话少叙.直接上题. (1) 最大子数组和 这个问题已经是toooooooooold了. 原问题是:给定一个数组.求一个子数组(连续的一段),它们的和最大.一些细节就是是否同意啥都不选,只是这个无关紧要.事实上不少书都把它作为动态规划的题目,我个人倒不太喜欢真的把它作为dp,之所以这么说,我认为作为dp反倒禁锢了人的思路.有点大材小用的感觉,而且真正的dp比这个复杂得多.这个题解法相当多.扔掉暴力的,也有非常多理解. (1.1)我自己yy的.事实上和(1.2)是一样的. 连续的一段数我们能够把开