【题解】 2015 ACM-ICPC Asia Regional Beijing Online (3+2)

来源:互联网 发布:软件开发的风险 编辑:程序博客网 时间:2024/05/16 11:50

【hiho 1227】 The Cats' Feeding Spots (二分+暴力枚举)


#1227 : The Cats' Feeding Spots

时间限制:1000ms
单点时限:1000ms
内存限制:256MB

描述

In Yan Yuan, the Peking University campus, there are many homeless cats. They all live happy lives because students founded a Cat Association to take care of them. Students not only feed them, but also treat their illness and sterilize some of them. Students make many feeding spots for the cats and cats always gather around those spots and make a lot of noise at night. Now the university authorities decide to restrict the number of feeding spots. This is the conversation between an officer and Rose Li, the director of Cat Association, and also a ACMer.

"Rose, From now on, you can't build any new feeding spots any more. But I want you to keep exactly N feeding spots, and you should make the area which contains the feeding spots as small as possible!"

"Oh, do you mean that we should find a smallest convex hull which contains N spots?"

"Convex hull? What is a convex hull? Please speak Chinese!"

"All right, forget the convex hull. So what do you mean the 'area', what's its shape?"

"It means... and the shape? Oh... let's do it this way: you can choose any feeding spot as center, and then draw a circle which includes exactly N spots. You should  find the smallest circle of such kind, and then we remove all feeding spots outside that circle."

Although this way sounds a little bit ridiculous, Rose still writes a program to solve the problem. Can you write the program?

输入

The first line is an integer T (T <= 50), meaning the number of test cases.

Then T lines follow, each describing a test case.

For each test case:

Two integer M and N go first(1 <= M, N <= 100), meaning that there are M feeding spots originally and Rose Li has to keep exactly N spots.

Then M pairs of real numbers follow, each means a coordinate of a feeding spot in Yan Yuan. The range of coordinates is between [-1000,1000]

输出

For each test case, print the radius of the smallest circle. Please note that the radius must be an POSITIVE INTEGER and no feeding spots should be located just on the circle because it's hard for the campus gardeners to judge whether they are inside or outside the circle.  If there are no solution, print "-1" instead.

样例输入
43 2 0 0 1 0 1.2 02 2 0 0 1 02 1 0 0 1.2 02 1 0 0 1 0
样例输出
121-1


题目大意是喂养一群流浪猫 由于喂养点太多 想要减少喂养点 每个点用坐标表示

现在有m个点 想要削减为n个点 方式是以任意一个喂养点为中心 做一个半径为整数的圆 在圆内的点被统计入内 并且圆上不可有点 问最小半径为多少

数据不大 纯粹暴力应该也行 用的暴力枚举+二分 枚举每个点为圆心 二分半径 找一个满足圆内n个点 圆上没有点的最小半径(圆心也算一个点


代码如下:


#include <bits/stdc++.h>#define ll long long#define INF 0x3f3f3f3f#define esp 1e-8#define fwrite() freopen("../out.out","w",stdout)#define fread() freopen("../in.in","r",stdin)using namespace std;typedef struct Point{    double x,y;    double operator - (const struct Point a)const    {        return sqrt((x-a.x)*(x-a.x)+(y-a.y)*(y-a.y));    }}Point;Point pt[111];int n,m;int dcmp(double x){    return x < -esp? -1: x > esp;}int can(double r,int pos){    int i,cnt = 0,f;    double x;    f = 1;    for(i = 0; i < m; ++i)    {        x = pt[i]-pt[pos]-r;        if(dcmp(x) == 0) f = 0;        if(dcmp(x) <= 0) cnt++;        //printf("%d %d %lf %lf\n",i,pos,pt[i]-pt[pos],r);    }    //printf("%d\n\n",cnt);    if(cnt == n && f) return 0;//圆内n个点并且圆上没点    if(cnt > n) return -1;//圆内点>n个 low = mid+1;    return 1;//圆内点< n个 或者圆上有点 high = mid-1;}int main(){    int r;    int t,i,k;    int low,high,mid,ans;    scanf("%d",&t);    while(t--)    {        scanf("%d %d",&m,&n);        for(i = 0; i < m; ++i) scanf("%lf %lf",&pt[i].x,&pt[i].y);        r = -1;        for(i = 0; i < m; ++i)        {            low = 1,high = 1500;//半径上下界初始化            ans = -1;            while(low <= high)            {                mid = (low+high)>>1;                k = can(mid,i);                if(!k)                {                    ans = mid;                    high = mid-1;                }                else if(k < 0) high = mid-1;                else low = mid+1;            }            if(ans != -1)            {                if(r == -1) r = ans;                else r = min(r,ans);            }        }        printf("%d\n",r);    }    return 0;}


【hiho 1228】 Mission Impossible 6(模拟)


#1228 : Mission Impossible 6

时间限制:1000ms
单点时限:1000ms
内存限制:256MB

描述

You must have seen the very famous movie series,"Mission Impossible", from 1 to 4. And "Mission Impossible 5" is now on screen in China. Tom Cruise is just learning programming through my MOOC course, and he wants a good score. So I made him divulge the story of "Mission Impossible 6".

In "Mission Impossible 6",  Ethan Hunt risks his life to install a mini camera in Bad Boss's room, in order to peep at the work Bad Boss does on his computer. Unfortunately, Bad Boss moves his desk to get more sunshine, and after that Ethan can't see the computer screen through the camera. Fortunately, Ethan can still see the keyboard. So, Ethan wants to know what Bad Boss writes on his computer by watching Bad Boss's keyboard inputs. That job is neither exciting nor risky, so it's really impossible for Ethan to accomplish --- that's why Tom Cruise wants to learn programming.

To simplified the problem, we assume that Bad Boss is editing a one line document, and the document consists of only lowercase letters. At first, there are nothing in the text editor window except a caret blinking at the left-most position (the starting position of the line). When Bad Boss input a lowercase letter, the letter appears at the right side of the caret, and then the caret moves to the right side of the letter just inputted. The text editor can switch between "insert mode" and "overwrite mode". When it's in "overwrite mode", the newly inputted letter will overwrite the letter which is on the right of the caret(if there is one). If it's in "insert mode", the newly inputted letter will be inserted before the letter which is originally on the right of the caret.

Besides inputting lowercase letters, Bad Boss can do some operations by inputting some uppercase letters, as described below:

'L' :  Moves the caret toward left by one letter. If the caret is already at the start of the line, then nothing happens.

'R':  Moves the caret toward right by one letter. If the caret is already at the end of the line(it means that there are no letters on the right side of the caret), then nothing happens.

'S':  Switch between "overwrite mode" and "insert mode". At the beginning, it's in "insert mode".

'D':  Delete a letter which is on the right of the caret. If the caret is already at the end of the line, then nothing happens. 'D' also has other effect which is described in 'C' operation below.

'B':  Delete a letter which is on the left of the caret. If the caret is already at the start of the line, then nothing happens.

'C': Copy something to the clipboard. At first , there is nothing in the clipboard, and the "copy status" of the editor is set to "NOTHING". When key 'C' is pressed:

If copy status is "NOTHING", copy status will be changed into "START", and the current position of caret is saved as "copy position 1".

if copy status is "START ", copy status will be changed into "NOTHING" and the letters between current caret position and the saved "copy position 1" will be copied into clipboard(The old content in the clipboard is replaced). If those two positions are the same, clipboard will be cleared.

Please note that , if any letter except 'L' , 'R' and 'D' is inputted when copy status is "START", copy status will changed into "NOTHING" immediately, not affecting the inputted letter taking its own effect as mention above. If 'D' is inputted when copy status is "START", copy status will changed into "NOTHING" immediately, and the letters between current caret position and "copy position 1" will be deleted.

'V': Paste the content in the clipboard into the right of the caret. If there is nothing in the clipboard, nothing happens. In "insertion mode", the pasted content is inserted. If it's in "overwrite mode" and there are k letters in the clipboard, then k letters will be overwrote. In "overwrite mode", if the number of letters on the right side of the caret is less then k, those letters will also all be replaced by the letters in the clipboard. After the paste operation, the caret moves to the right of the last pasted letter.

The content of the text line will never exceed M letters. Any input which will cause the content exceed M letters must be ignored. Especially, when you paste, you either paste all content in the clipboard, or paste nothing due to the text length limit.

输入

The first line of the input is a integer T(T <= 20), meaning that there are T test cases. The T lines follow, and each line is a test case.

For each test case:

A integer M (0 <= M <= 10,000) goes first ,meaning the text length limitation. Then some letters follow, describing what Bad Boss inputs. The total number of letters in one test case is no more than 10,000.

输出

For each test case, print the result which Bad Boss gets. If the result is nothing, print "NOTHING".

样例输入
8100 abcdeLCLLD5 abcLkjff15 abcBBdeLLDDxzDDDDRRRR25 abcdefgLLLSxyzSLLku20 abcdefgLLCkLLCRRRRRCLV20 abcdefgLLCkLLCRRRRCLLLSV30 abcdeCLLCRRVCLRCabVkz10 abcBBBLB
样例输出
abeabkjcaxzabcdxkuyzabcdekfekfggabcdeekfgabcdedeabkzNOTHING


模拟一个文本编辑器

小写字母为输入 光标为插入模式时 在光标位置插入 为重写模式时 覆盖光标处字符

大写L 光标左移 R光标右移 S为转换光标模式

D删除光标右边字母 B删除左边字母

C为复制 初始为关 按一下变开 再按一下转换为关 同时把选择区内的字符串存取剪切板(如果粘贴板之前有东西 替换掉

C为开时 如果出现L R D外的字母 立即转换为关 不产生任何作用 LR正常执行 D变为删除选取内的字符串

V为粘贴 如果光标为插入 把剪切板内容插入到当前光标位置 如果光标为覆盖模式 假设剪切板有k个字母 当前光标往后k个字母被替换掉 不足k个 也被k个替换 粘贴完成后光标移动到粘贴上的字符串的最右端

此外有字符数量限制m 任何导致超过m的操作将被取消 特别的 对于V 如果导致超过m 不会粘贴上任何东西


写完不断改就是了……模拟题都这样。。。

还有我做法中很多strcpy 很耗时间 但不可缺(至少对于我这种写法) 因为没有的话处理过程中结果串会出现很多本不该存在的后缀 如果不小心改了个/0 就会让他们暴露出来 也可以采用不断填'/0' 自己摸索


代码如下:

#include <bits/stdc++.h>#define ll long long#define INF 0x3f3f3f3f#define esp 1e-8#define fwrite() freopen("out.out","w",stdout)#define fread() freopen("in.in","r",stdin)using namespace std;char str[1111111],opr[1111111],tmp[1111111],clp[1111111],us[1111111];int mlen,pos,cpos,len,clen;bool cpy,mode;void Write(char ch){    cpy = 0;    if(mode)    {        if(len == mlen && pos == len) return;        str[pos++] = ch;        if(pos-1 == len) str[++len] = 0;    }    else    {        if(len == mlen) return;        strcpy(tmp,str+pos);        str[pos++] = ch;        strcpy(str+pos,tmp);        len++;    }}void Delete(){    if(cpy)    {        strcpy(tmp,str+max(pos,cpos));        strcpy(str+min(pos,cpos),tmp);        len -= abs(pos-cpos);    }    else    {        if(pos == len) return;        strcpy(tmp,str+pos+1);        strcpy(str+pos,tmp);        len--;    }    cpy = 0;}void Back(){    cpy = 0;    if(pos)    {        strcpy(tmp,str+pos);        pos--;        strcpy(str+pos,tmp);        len--;    }}void Search(){    cpy = 0;    mode = !mode;}void Copy(){    if(cpy)//START    {        strcpy(clp,str+min(pos,cpos));        strcpy(clp+abs(cpos-pos),us);        clen = abs(cpos-pos);        cpy = 0;    }    else//NOTHING    {        cpos = pos;        cpy = 1;    }}void Vis(){    cpy = 0;    if(!clen) return;    if(mode)    {        if(pos+clen > mlen) return;        strcpy(tmp,str+pos+clen);        strcpy(str+pos,clp);        strcpy(str+pos+clen,tmp);    }    else    {        if(len+clen > mlen) return;        strcpy(tmp,str+pos);        strcpy(str+pos,clp);        strcpy(str+min((mlen-(len-pos)),pos+clen),tmp);    }    strcpy(str+mlen,us);    len = strlen(str);    pos = min(mlen,pos+clen);}int main(){    int t,i;    scanf("%d",&t);    memset(us,0,sizeof(us));    while(t--)    {        scanf("%d",&mlen);        scanf("%s",opr);        clen = len = cpos = cpy = mode = pos = 0;        memset(str,0,sizeof(str));        memset(clp,0,sizeof(clp));        memset(tmp,0,sizeof(tmp));        for(i = 0; opr[i]; ++i)        {            if(opr[i] >= 'a' && opr[i] <= 'z') Write(opr[i]);            else if(opr[i] == 'L')            {                if(pos) pos--;            }            else if(opr[i] == 'R')            {                if(pos < mlen && pos < len) pos++;            }            else if(opr[i] == 'D') Delete();            else if(opr[i] == 'B') Back();            else if(opr[i] == 'S') Search();            else if(opr[i] == 'C') Copy();            else if(opr[i] == 'V') Vis();        }        if(!len) puts("NOTHING");        else puts(str);    }    return 0;}

【hiho 1233】 Boxes(n进制+bfs预处理)


#1233 : Boxes

时间限制:1000ms
单点时限:1000ms
内存限制:256MB

描述

There is a strange storehouse in PKU. In this storehouse there are n slots for boxes, forming a line. In each slot you can pile up any amount of boxes. The limitation is that you can only pile a smaller one above a bigger one, in order to keep balance. The slots are numbered from 1 to n. The leftmost one is slot 1.

At first there is exactly one box in each slot. The volume of the box in slot i is vi. As a virgo, you decide to sort these boxes by moving some of them. In each move you can choose a slot and move the top box in this slot to an adjacent slot (of course you can only put it on the top). You should ensure that the limitation mentioned above is still satisfied after this move. After the sort operation, there should be exactly one box in each slot, and for each pair of adjacent slots, the box in the left one should be smaller than the box in the right one.

Your task is to calculate the minimum number of moves you need to sort the boxes.

输入

In the first line there’s an integer T(T≤6000), indicating the number of test cases. The following 2T lines describe the test cases.

In each test case, the first line contains an integer n, indicating the number of slots. The second line contains n integers v1,v2…vn, indicating the volume of the boxes. It is guaranteed that all vi in a test case are different.

Please note that n<8,0≤vi≤104

输出

For each test case, print a line containing one integer indicating the answer. If it’s impossible to sort the boxes, print -1.

样例输入
432 1 327 8210000 1000397 96 95
样例输出
40-120


比赛时没想出怎么做 赛后学长们给讲的 由于状态数很少 查询很多 所以要预处理出所有查询的结果 然后O(1)查 按这个思路自己写了写 可能算法不是很优美

题意是给你n个盒子 想要把他们排成从左到右编号从小到大 排序过程是由移动盒子达成 移动盒子时只能左移或右移一位 并且只能把小盒子移到大盒子上 进制每位表示该盒子位置 然后模拟移动 广搜从目标状态回撤出所有初始状态 并记录下步数 之后每次输入转换成1~n 输出即可


代码如下:

#include <bits/stdc++.h>using namespace std;int sp[2100000];int num[9],dex[9],n;int Get(int *t)//8进制转十进制{    int x = 0;    for(int i = 7; i >= 1; --i)    {        x = x*8+t[i];    }    //cout<<x<<endl;    return x;}//void Print(int x)//{//    while(x)//    {//        printf("%d",x%8);//        x /= 8;//    }//    puts("");//}void Init(){    queue <int> q;    int i,j,pre,x,nw;    int tmp[9];    bool l,r;    for(i = 1; i <= 7; ++i)//可达的最终结果预处理 即1 12 123 1234...情况    {        for(x = 0, j = i; j >= 1; --j)        {            x = x*8+j;        }        sp[x] = 0;        q.push(x);        //printf("%d\n",x);    }    while(!q.empty())    {        pre = q.front();        q.pop();        nw = pre;//        if(sp[nw] == 2)//        {//            Print(nw);//        }        for(i = 1; i < 9; ++i)//十进制转八进制        {            tmp[i] = pre%8;            pre/=8;        }        for(i = 1; tmp[i]; ++i)//枚举每一个盒子(如果存在        {            l = r = 1;            for(j = 1; j < i; ++j)//枚举比他小的 如果在他左边 无法左移 右边 无法右移 和他在一个位置(必在他上面 无法移动            {                if(tmp[j] == tmp[i])                {                    l = 0,r = 0;                    break;                }                if(tmp[j] == tmp[i]-1) l = 0;                else if(tmp[j] == tmp[i]+1) r = 0;            }            if(l && tmp[i] > 1)//左边盒子比该盒大 并且该盒不在首位 可左移            {                tmp[i]--;                x = Get(tmp);                if(sp[x] == -1)                {                    sp[x] = sp[nw]+1;                    q.push(x);                }                tmp[i]++;            }            if(r && tmp[tmp[i]+1])//右边盒子比该盒大 并且该盒不在末位(存在第tmp[i]+1个盒子) 可右移            {                tmp[i]++;                x = Get(tmp);                if(sp[x] == -1)                {                    sp[x] = sp[nw]+1;                    q.push(x);                }                tmp[i]--;            }        }    }}int main(){    memset(sp,-1,sizeof(sp));//预处理所有状态不可达    Init();    int t,i,j,x,y,m;    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        m = 1;//最大盒子编号        for(i = 1; i <= n; ++i)        {            scanf("%d",&num[i]);            if(num[m] < num[i]) m = i;        }        x = -1;//已排序的最大盒子编号        memset(dex,0,sizeof(dex));        for(i = 1; i <= n; ++i)        {            y = m;            for(j = 1; j <= n; ++j)            {                if(num[j] <= num[y] && num[j] > x)//找出未排序的最小盒子(满足[已排序最大编号< x<= 最大编号] 的最小x)                {                    y = j;                }            }            x = num[y];            dex[i] = y;//转化为1~n        }        printf("%d\n",sp[Get(dex)]);//输出达到改状态需要的步数    }    return 0;}


【hiho 1234】 Fractal(二分+精度)


#1234 : Fractal

时间限制:1000ms
单点时限:1000ms
内存限制:256MB

描述


This is the logo of PKUACM 2016. More specifically, the logo is generated as follows:

1. Put four points A0(0,0), B0(0,1), C0(1,1), D0(1,0) on a cartesian coordinate system.

2. Link A0B0, B0C0, C0D0, D0A0 separately, forming square A0B0C0D0.

3. Assume we have already generated square AiBiCiDi, then square Ai+1Bi+1Ci+1Di+1 is generated by linking the midpoints of AiBi, BiCi, CiDi and DiAi successively.

4. Repeat step three 1000 times.

Now the designer decides to add a vertical line x=k to this logo( 0<= k < 0.5, and for k, there will be at most 8 digits after the decimal point). He wants to know the number of common points between the new line and the original logo.

输入

In the first line there’s an integer T( T < 10,000), indicating the number of test cases.

Then T lines follow, each describing a test case. Each line contains an float number k, meaning that you should calculate the number of common points between line x = k and the logo.

输出

For each test case, print a line containing one integer indicating the answer. If there are infinity common points, print -1.

样例输入
30.3750.0010.478
样例输出
-1420

给一个小数k∈[0,0.5) 图右下角坐标为(0,0) 表示画一条线x = k 问与该图有几个交点 如果与图中某竖线段重合 输出-1

观察图可得知 [0,0.5]裸二分 二分中出现mid = k 输出-1 出现mid>k 说明在当前竖线左边 输出4*cnt(二分次数) 

最多八位小数 打个表也行 二分需要注意精度 1e-9不够。。。


代码如下:

#include <bits/stdc++.h>#define ll long long#define INF 0x3f3f3f3f#define esp 1e-10#define fwrite() freopen("../out.out","w",stdout)#define fread() freopen("../in.in","r",stdin)using namespace std;int dcmp(double x){    return x < -esp? -1: x > esp;}int main(){    //fread();    int t,cnt;    double x,l,r,m;    scanf("%d",&t);    while(t--)    {        scanf("%lf",&x);        cnt = 1;        l = 0;        r = 0.5;        if(!dcmp(x))        {            puts("-1");            continue;        }        while(1)        {            m = (l+r)/2;            if(!dcmp(m-x))            {                cnt = 0;                break;            }            else if(dcmp(m-x)>0)            {                break;            }            else            {                cnt++;                l = m;            }        }        if(!cnt) puts("-1");        else printf("%d\n",cnt*4);    }    return 0;}

【hiho 1236】 Scores(bitset+分区间二分)


#1236 : Scores

时间限制:4000ms
单点时限:4000ms
内存限制:256MB

描述

Kyle is a student of Programming Monkey Elementary School. Just as others, he is deeply concerned with his grades.

Last month, the school held an examination including five subjects, without any doubt, Kyle got a perfect score in every single subject.

There are n students took part in this examination(not including Kyle), and everyone got an integer between 1 to m as the score of one subject.

Now, looking at the grade table of these n students, Kyle wants to know how many students still did no better than him even if his scores are something else – Here, “no better” means there is no subject in which the student got strictly greater score than Kyle.

输入

There are multiple test cases.

The first line of the input contains an integer T (T <= 3) which means the number of test cases.

The first line of each test case contains two integers, n, m(n, m≤ 50,000), which are the number of students and the perfect score of each subject.

In the next n lines, each line consists of five integers, indicating a student’s scores.

Then one line follows. This line contains an integer q(q≤ 50,000) indicating the number of queries.

In the next q lines, each line contains five integers as well, representing a query. Each query indicates a set of scores, and for each query, you should figure out that if Kyle's grade is this set of scores, how many students still did no better than him. But for the sake of security, only the first query is in its original form, and other queries are encrypted. To decrypt a query, you must let each integer in the query do xor operation with the answer of last query. It's guaranteed that all the decrypted queries contain integers between 1 and 50000.

输出

For each test case, you should output q lines as the answer for all queries.

提示

In case 1, there are two students with different scores and the scores of the first student (1, 1, 1, 1, 1) are not larger than the first query (1 1 1 1 1) in every subject, so the answer for this query is 1.

After having xor operation with the last answer 1, the second query (3,3,3,3,3) will be decrypted into (2, 2, 2, 2, 2). Because both students’ scores are no better than  (2, 2, 2, 2, 2), so the answer for query 2 is 2.

样例输入
22 31 1 1 1 12 2 2 2 2 21 1 1 1 13 3 3 3 33 51 1 1 1 11 1 1 1 11 2 3 4 521 1 1 1 11 1 1 1 1
样例输出
1222

题目大意是有五门课程 n个学生 每个学生对应5个分数 有q次查询 问五门课程都不超过(小于等于)给出分数的人数

要统计的是5门课都小于等于给定分数的学生数 总共最多50000名学生 可以用bitset容器 存5个n位的二进制 1~5表示1~5门课程 每个二进制1表示该生该分数<=给定分数 0表示该生该分数>给定分数 五个二进制且一下 最后的1的个数就是5门课程都小于等于给定分数的人数 这是最根本的做法 但纯这样做会超时 可以分段 

先把五个分数分别排序 每sqrt(n)个人为一段 bit[i][j]表示第i门从小到大第( (i-1)*sqrt(n),i*sqrt(n) ]对应第几名学生得到的二进制

这样每次先二分 找到第i门课程第一个大于给定分数的下标 然后在该下标范围内枚举 统计人数即可

有个坑点是出了第一次查询 之后每门成绩都要跟前一次结果异或一下。。。


代码如下:

#include <bits/stdc++.h>#define MAXN 50500using namespace std;struct Student{    int id,s;    bool operator < (const struct Student a)const    {        return s == a.s? id < a.id: s < a.s;    }};Student s[6][MAXN];//存放1~5门课学生成绩与编号bitset <MAXN> bit[6][233];//将学生分段 bit[i][j] 表示第i门课程 第[1,sqrt*j]名学生bitset <MAXN> ans;//最终结果int b[6];int Lowerbound(Student *a,int x,int l,int r)//二分找到最后一个小于等于给定分数的区间(换句话说这之前的区间都满足 可统一累加上 之后余下的小于给定分数的学生标号需要单独跑循环{    int id = 0,mid;    while(l <= r)    {        mid = (l+r)>>1;        if(a[mid].s <= x)        {            id = mid;            l = mid+1;        }        else r = mid-1;    }    return id;}int main(){    int t,n,m,q,i,j,k,tmp,last,sq,re;    scanf("%d",&t);    while(t--)    {        scanf("%d %d",&n,&m);        for(i = 1; i <= n; ++i)        {            for(j = 1; j <= 5; ++j)            {                scanf("%d",&s[j][i].s);                s[j][i].id = i;            }        }        for(i = 1; i <= 5; ++i) sort(s[i]+1,s[i]+n+1);        sq = sqrt(n);        for(k = 1; k <= 5; ++k)//每门课程以sqrt为单位区间长度分区        {            for(i = 1; (i-1)*sq <= n; ++i)            {                bit[k][i].reset();                bit[k][i] = bit[k][i-1];//表示该门课前[1,sq*i]名学生                for(j = sq*(i-1)+1; j <= sq*i && j <= n; ++j)                {                    bit[k][i].set(s[k][j].id);                }            }        }        scanf("%d",&q);        last = 0;//前一个答案        while(q--)        {            for(i = 1; i <= 5; ++i)            {                scanf("%d",&b[i]);                b[i] ^= last;            }            tmp = Lowerbound(s[1],b[1],1,n);//二分出第一个出现大于给定分数的区间            tmp /= sq;            ans = bit[1][tmp];            for(j = tmp*sq+1; j <= n && s[1][j].s <= b[1]; ++j)//                ans.set(s[1][j].id);            for(i = 2; i <= 5; ++i)//第2~5门课同上            {                tmp = Lowerbound(s[i],b[i],1,n);                tmp /= sq;                bitset <MAXN> tbs;                tbs = bit[i][tmp];                for(j = tmp*sq+1; j <= n && s[i][j].s <= b[i]; ++j)                    tbs.set(s[i][j].id);                ans = ans&tbs;            }            re = ans.count();            printf("%d\n",re);            last = re;        }    }    return 0;}




0 0
原创粉丝点击