记一个问题的AC

今天突然做一道LCT的染色问题的时候突然想到一个两个月前一道没有AC的题目。

链接

大意是,给一个长度为10^4的序列,最多有255个不同的数字,有最多10^5次方个询问,对于每个询问 l,r 输出[l,r]中不同数字的数目。

记得最初的想法是  用f[i][j],存下数字i的第j次出现位置的下标 ,对每次询问,二分查找,判断每个数字i是否存在在[l,r]内的下标。

时间复杂度是最多是 O((10^5)*255*log(10^4)) ,结果比赛的时候超时了,加了读入优化还是不行。

由于比赛的OJ运行偏慢,1s的时限  比赛结束,只有3个人AC,最快的400ms,有一个刚刚好1000ms。

于是我发了个帖子,询问答案,果然得到了更好的思路:

1.

离散化,C[i][j]::A[1]..A[i]中值为j的数的个数
 则数k在[L..R]中出现 <=> C[i][R]-C[i][L-1]>0.
  一次询问时间(255),时间复杂度是O(10^5*255)

已经优化了一点点

代码:

#include <cstdio>
#include <cstdlib>
#include <time.h>
#include <iostream>
using namespace std;
const int INF = 100009;

int f[INF][300],pos[INF];
int g[INF];
int n, m, tol;
inline void rd (int &xx) {
    char ch = getchar();
    while (ch < ‘0‘ || ch > ‘9‘) ch = getchar();
    for (xx = 0; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar() )
        xx = xx * 10 + (ch - ‘0‘);
}
char o[35];
inline void putnum (int x) {
    if (x == 0) {putchar (‘0‘); return;}
    int i;
    for (i = 0; x != 0; i++, x /= 10) o[i] = x % 10 + ‘0‘ ;
    for (i--; i >= 0; i--) putchar (o[i]);
    putchar (10);
}
int main() {
    rd (n); rd (m);
    for (int i = 1; i <= n; i++) {
        rd (g[i]);
        if (!pos[g[i]])    pos[g[i]] = ++tol;
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= tol; j++)
            f[i][j] = f[i - 1][j] + (pos[g[i]] == j);
    }
    for (int i = 1, l, r; i <= m; i++) {
        int ans = 0;
        rd (l), rd (r);
        for (int j = 1; j <= tol; j++)
            if (f[r][j] - f[l - 1][j]) ans++;
        putnum (ans);
    }
    return 0;
}

可是在加上了读入和输出优化和依旧超时!

2.

把所有询问存下来,并按照l由小到大的顺序依次回答。当左端点为t时,考虑一个数组b[],若b[i]=1则表示a[i]在a[t]到a[i-1]都没出现过,否则b[i]=0。
那么任意一个左端点l=t,右端点r的询问都可以查询b[1]到b[r]的和得到答案。这个求区间和的操作可以用树状数组或线段树来解决。
当回答完l=t的询问,要回答l=t+1的询问时,涉及到b[]数组的修改。发现只需要把b[t]由1变0,把b[right[t]]由0变1,其中a[t]右边第一个和它相等的数是a[right[t]],可以预处理出来。这两个修改对于树状数组来说太容易了,然后本题就做完了。
补一句,如果题目要求强制在线,就把树状数组换成可持久化线段树,就搞定了。

时间复杂度可以优化至 O(NlogN+Q)

思路真是太棒了!看完这个我感觉这就是我想要的。

于是再经过无数TLE,优化,TLE,再优化终于AC了,并且只用了234ms!

#include <cstdio>
#include <cstdlib>
#include <time.h>
#include <iostream>
using namespace std;

const int INF = 100009;

int b[INF], ans[INF], qhead[INF], qr[INF], skip[INF];
int g[INF], ne[INF], last[INF];
int n, m, tol;
inline void rd (int &xx) {
    char ch = getchar();
    while (ch < ‘0‘ || ch > ‘9‘) ch = getchar();
    for (xx = 0; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar() )
        xx = xx * 10 + (ch - ‘0‘);
}
char o[35];
inline void putnum (int x) {
    if (x == 0) {putchar (‘0‘); return;}
    int i;
    for (i = 0; x != 0; i++, x /= 10) o[i] = x % 10 + ‘0‘ ;
    for (i--; i >= 0; i--) putchar (o[i]);
    putchar (10);
}
int main() {
    rd (n); rd (m);
    for (int i = 1; i <= n; i++) rd (g[i]);
    for (int i = 1, x; i <= m; i++) {
        rd (x), rd (qr[i]);
        skip[i] = qhead[x];
        qhead[x] = i;
    }
    for (int i = 1; i <= n; i++) {
        int t = g[i];
        if (last[t] == 0) for (int x = i; x <= n; x += x & -x) ++b[x];
        ne[last[t]] = i, last[t] = i;
    }
    for (int i = 1; i <= n; i++) {
        if (qhead[i])
            for (int t = qhead[i]; t; t = skip[t])
                for (int x = qr[t]; x > 0; x -= x & -x) ans[t] += b[x];

        for (int x = i; x <= n; x += x & -x) --b[x];
        if (ne[i] != 0) for (int x = ne[i]; x <= n; x += x & -x) ++b[x];
    }
    for (int i = 1; i <= m; i++)
        putnum (ans[i]);

}

感谢回答我问题的 nodgd 和  Hoblovski

时间: 2024-10-13 16:48:04

记一个问题的AC的相关文章

记一个html5 drawImage的问题NS_ERROR_NOT_AVAILABLE:

本地html文件,在firefox下打开,调用到drawImage报错:NS_ERROR_NOT_AVAILABLE. 不能放到桌面,换个目录就好了,路径问题. 记一个html5 drawImage的问题NS_ERROR_NOT_AVAILABLE:,布布扣,bubuko.com

记一个使用Client Object Model上传文件的小例子

1. 新建一个C#的Console project. 2. 给project 添加reference: Microsoft.SharePoint.Client Microsoft.SharePoint.Runtime 3. 修改project的属性: Platform target – x64 Target framework – .NET Framework 4 4. 修改代码如下: using System; using System.IO; using System.Net; using

记一个界面刷新相关的Bug

今天遇到一个比较有意思的bug, 这里简单记录下. Bug的症状是通过拖拉边框把我们客户端主窗口拖小之后,再最大化,会发现窗口显示有问题, 看起来像是刷新问题, 有些地方显示的不对了. 这里要说明的是我这里的主窗口是非常复杂的窗口, 里面集成了很多组件(cpmponent),有很多层的子窗口. 这个问题只有在特定条件下才会发生, 正常情况下都是好的. 遇到这种问题,我们怎么处理? 首先当然是观察症状, 究竟是刷新问题, 还是Layout出错了. 我们可以通过Spy++查看窗口层次是不是正确, 窗

记一个社交APP的开发过程——基础架构选型(转自一位大哥)

记一个社交APP的开发过程——基础架构选型 目录[-] 基本产品形态 技术选型 最近两周在忙于开发一个社交App,因为之前做过一点儿社交方面的东西,就被拉去做API后端了,一个人头一次完整的去搭这么一套东西,上面也没有PM和各种催促,过程还是很轻松愉快充满乐趣的,现在后端已经基本完成,下周会进入联调测试的阶段,有些东西想写一写记录一下,先从技术选型开始. 基本产品形态 产品的基础功能无非是所有社交App都具备的那些东西,新鲜事.好友关系(同微博一样,单向follow).地理位置(当前的位置.你附

记一个python+sqlalchemy+tornado的一个高并发下,产生重复记录的bug

场景:在用户通过支付通道支付完成返回时,发现我收到的处理数据记录中有两条同样的数据记录, 也就是同一笔钱,我数据库中记为了两条一样的记录. tornado端代码 from tornado import gen from tornado.concurrent import run_on_executor class processNetPay(BaseHandler): '''处理指定订单,指定支付请求,返回处理结果 ' 返回包含订单信息与用户信息体 ''' @tornado.web.asynch

记一个网络传输功能的实现过程

写在前面的话:功能是基于C/S模型的网络传输实现,要求是服务器端可以在局域网中任何机子上运行,客户端启动后自动寻找服务器端进行连接,之后,服务器端向已经连接的客户端发送命令,客户端根据命令执行相应的操作(即发送某个约定文件夹下的所有文件),并且客户端不需要用户操作. 1.思路 首先,对于这个功能的实现思路如下,因为服务器不确定在哪个机子上,所以为了寻找到服务器端,客户端需要发送广播消息,并且为了维护客户端在线,广播消息需要实现成心跳包(即定时发送广播消息).服务器监听心跳包,如果是新加入的客户端

开博第一篇:记一个前端实现的“换一换”功能

需求的极简概要:实现“换一换”按钮的功能,点击之后,换另一批对应的品牌 刚开始的时候考虑使用ajax请求数据,之后通过js在页面上填充到指定位置,但是真是懒得给这个ajax请求单独再配一个请求映射了,干脆直接在后台把需要的内容全部拼成JSON字符串,直接在前台解析,分页. 页面比较简单,就不上html代码了,大概思路就是:两个“换一换”按钮分别对应两套数据,共用一个分页的方法,分别传入各自的页数,显示对应页数的内容.当然了,实现“换一换”的方法多种多样,我在此只是记录一下自己的思路,欢迎批评指教

记一个小错误:&#39;numpy.ndarray&#39; object is not callable

错误在于mfcc是已经定义的函数,所以变量名改为wav_mfcc,问题就解决了. 参考博客: https://blog.csdn.net/Olaking/article/details/43199003 记一个小错误:'numpy.ndarray' object is not callable 原文地址:https://www.cnblogs.com/yuren1998/p/11558700.html

记一个推导

看一个图形学的课程实在是槽点太多,推导各种省略,愣是没看懂怎么又关系的. 考虑一个b向量绕a旋转theta角, 第一行是b垂直于a的分量,记为b⊥   .等式右边加号左侧是b⊥*cosθ,加号右边是 c*sinθ, 值得注意的是c = a × b = absinΦ (这里Φ为a和b的夹角),图中是将叉乘写为对偶矩阵的形式. 显然 c*sinθ 代替的是 b⊥*sinθ, 课程前面提到a和b都是单位向量,所以影响c大小的是a × b = ab*sinΦ,同样b⊥ = b*sinΦ,所以大小上两者是