沈阳集训day1

来源:互联网 发布:linux的ftp怎么开启 编辑:程序博客网 时间:2024/04/30 00:41

吐槽&记录
人生真是很多意想不到的事情,来的第一天去搞事,跑遍整个沈阳市郊,有个万达,附近的internet bar好少,而且普遍进不去,后来颓了一下午,把营员证搞掉,晚上吃的外卖,真难吃,本来说要开开营仪式,结果衡水的没来(大佬还没来),所以就不开了。晚自习的时候已经有大神在装逼了,初三的学弟虐场,回寝室的,浴室环境很差,完全可以用来拍鬼片,没买拖鞋,用麦当劳的装可乐的塑料袋当了一次拖鞋,晚上晚自习的时候就想着回去一定要好好休息,明天的题应该不会太难,要好好发挥,结果回寝室有长春十一中的大佬开热点,于是用流量打了局lol,卡到人物在地上磨着走,然后陪室友打cs到深夜,半死半活地睡去,已经有室友在打鼾了
第二天丧心病狂的有人在五点钟闹铃(前一天赶飞机),被闹醒后半个小时睡不着,然后刚睡了一会儿,有个人6点的闹铃又响了,时候他说是他故意不关的(想打他),然后在床上翻来覆去躺了二十分钟,六点二十起床,六点五十去食堂,食堂上面有四个大字(清真食堂),很清真地吃了一顿,然后半睡半醒地去了机房,考试的时候昏昏欲睡(所以就睡了),最后最水的一道题都没做出来,成绩出来之后果然是初中的学弟全场rank1,感到深深的差距和压力,中午回去决心补觉,室友都没睡,吵吵着玩儿手机玩儿电脑,写题,起床之后还是精神萎靡,胡教说到时候讲课的时候,要给他们建议,电脑广播窗口都开小窗,这样你们既可以边学,也可以边听,这样的好处就是如果太简单,你们也可以刷自己的题,我在旁边笑了笑。
下午没在机房,没有电脑,也没有什么小窗教学,东北的气候很好,天气很好,空气很好,阳光很好,从阶梯教室照进来暖洋洋的,正适合(睡觉)学习,内容太难,数学本来就差,根本听不懂莫比乌斯反演和卷积。欧拉函数,积性函数,离散对数这些也是勉强有一些听懂,下课时个别大佬响亮的掌声吵醒了众多睡觉的人,课后胡教说你以后别来了,来了也是睡觉,我心里想着其他一堆睡觉的,我只睡了不到半个小时,很伤心,可能是自己不争气吧,毕竟太弱了,qq因为异地登陆被冻结,我失去很多联系,着实难过,感觉是被世界遗弃的弱者


好吧,吐槽也吐槽了,写题解吧
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
看到这篇博客的肯定会觉得这啥水题,这么垃圾(我能说什么,t3对我来说很难啊,我到现在不会tarjan缩点)


首先看t1,用map存一下就行了,建一个int->int的map,每有新元素就m[i]++,然后打擂台找最大就行,几行代码就解决了,其实也就是存很多次上升序列,最多有多少就要存多少个,比如
1 4 2 3 8 6 0 9 9 6 4
会在
0 1 2 3 4 6 8 9 4 6 9
的时候收益最大
所以我们可以这样看
(0 1 2 3 4 6 8 9)(4 6 9)
因为后面括号里的数放到前面去是对答案没有贡献的,故这样是一种最优的方式,如果有三个重复的,比如
(0 1 2 3 4 5 6 7 8 9)(4 5 6)(4 5)
故只需要找到出现次数最多的数出现的次数即可
1A代码:

#include<cstdio>#include<cstring>#include<iostream>#include<map>using namespace std;map<int,int>m;int n,temp,maxn;int main(){    scanf("%d",&n);    for(register int i=1;i<=n;i++){        scanf("%d",&temp);m[temp]++;        maxn=max(maxn,m[temp]);    }    printf("%d",n-maxn);    return 0;}

接着来看t4,这道题只需要保存pos,然后贪就行了,我都不好意思讲,大概是这么个意思
这里写图片描述

对于A到B这种情况,也就是pos处于L和R之间的,就continue,如果L大于pos,就加L-pos,更新pos,如果R小于pos,就加pos-R,更新pos

#include<cstdio>#include<cstring>#include<iostream>using namespace std;int n,m,l,r,nowl,nowr,cnt,pos;int main(){    scanf("%d%d",&n,&m);    scanf("%d%d",&l,&r);pos=l;    for(register int i=1;i<=n-1;i++){        scanf("%d%d",&nowl,&nowr);        if(nowl>pos){            cnt+=nowl-pos;            pos=nowl;        }else if(nowr<pos){            cnt+=pos-nowr;            pos=nowr;        }else{            continue;        }    }    printf("%d",cnt);    return 0;} 

Microsoft Edge自动保存了我的线上草稿???我又不小心关了浏览器竟然没掉???


让我们来看第二题(这也是我目前能解决的最后一题了)

回忆一遍题,是叫我们求[a,b]的区间异或(XOR)上一个数的异或和。
F.自然可以想到转化为求[1,b]的异或和减去[1,a-1]的异或和
S.画一个表(t是ten,为了工整)
__t 9 8 7 6 5 4 3 2 1
1 0 0 0 0 0 0 0 0 0 1
2 0 0 0 0 0 0 0 0 1 0
3 0 0 0 0 0 0 0 0 1 1
4 0 0 0 0 0 0 0 1 0 0
5 0 0 0 0 0 0 0 1 0 1
6 0 0 0 0 0 0 0 1 1 0
7 0 0 0 0 0 0 0 1 1 1
8 0 0 0 0 0 0 1 0 0 0
9 0 0 0 0 0 0 1 0 0 1
t 0 0 0 0 0 0 1 0 1 0
可以发现如下几条规律
首先,每一列的前导0的个数在列数为i时为2^(i-1)-1
然后,对于第i列,循环为2^i,其中每个循环有2^(i-1)个1,也有相同数量的0,比如第一列的循环节为10,第二列为1100,我们规定循环节从1开始,因为求出前导零后将删去前导零的个数


所以我们要做的,就是计算出1到b的每一列的0个数和1个数,计算出1到a-1的0个数和1个数,然后a到b的零个数应该为1到b的零个数减去1到a-1的零个数,a到b的1个数求法相同,求出a到b的0和1的个数后,再把c用二进制表示出来,如果c的第i位为0的话,那么该位对答案的贡献为a到b的第i位的1的个数乘以该位的意义(意义是指二进制101中左边的1表示4,右边的表示1,也就是2^(i-1))
结果记得取模

#include<cstdio>#include<iostream>#include<cstring>#include<map>#define idy 23333333333333333using namespace std;int T;long long a,b,c;long long cnt_1_b[64][2],cnt_1_a[64][2],cnt[64][2],cs[64];map<long long,int>m;long long final;int maxb,maxa,maxn,maxc;long long lowbit(long long x){return x&-x;}void init(){    memset(cnt,0,sizeof(cnt));    memset(cnt_1_a,0,sizeof(cnt_1_a));    memset(cnt_1_b,0,sizeof(cnt_1_b));    maxb=-1;    maxn=-1;    long long te=1;    int mp=1;    while((te<<1)<=b)mp++,te<<=1;    maxb=max(maxb,mp);    maxn=max(maxn,maxb);    for(int i=1;i<=maxb;i++){        long long tt=(1<<(i-1))-1;        te=(b-tt)/(1<<i);        cnt_1_b[i][0]+=tt;        cnt_1_b[i][1]+=te*(1<<(i-1));        cnt_1_b[i][0]+=te*(1<<(i-1));        long long mp=(b-tt)%(1<<i);        if(mp<=(1<<(i-1))) cnt_1_b[i][1]+=mp;        else{            cnt_1_b[i][1]+=(1<<(i-1));            cnt_1_b[i][0]+=(mp-(1<<(i-1)));        }    }    mp=1,te=1;    while((te<<1)<=a)mp++,te<<=1;    maxa=-1;    maxa=max(maxa,mp);    maxn=max(maxn,maxa);    for(int i=1;i<=maxa;i++){        long long tt=(1<<(i-1))-1;        te=(a-tt)/(1<<i);        cnt_1_a[i][0]+=tt;        cnt_1_a[i][1]+=te*(1<<(i-1));        cnt_1_a[i][0]+=te*(1<<(i-1));        long long mp=(a-tt)%(1<<i);        if(mp<=(1<<(i-1))) cnt_1_a[i][1]+=mp;        else{            cnt_1_a[i][1]+=(1<<(i-1));            cnt_1_a[i][0]+=(mp-(1<<(i-1)));        }    }    for(int i=maxa+1;i<=maxb;i++){        cnt_1_a[i][0]=a;    }    for(int i=1;i<=maxn;i++){        cnt[i][1]=cnt_1_b[i][1]-cnt_1_a[i][1];        cnt[i][0]=cnt_1_b[i][0]-cnt_1_a[i][0];    }}void solve(){    memset(cs,0,sizeof(cs));    int te,mp;    te=c;    while(te){        mp=lowbit(te);        cs[m[mp]]=1;        te-=mp;    }    final=0;    mp=1,te=1;    while((te<<1)<=c)mp++,te<<=1;    maxc=-1;    maxc=max(maxc,mp);    maxn=max(maxn,maxc);    if(maxc>maxb){        for(int i=maxb+1;i<=maxc;i++){            cnt[i][0]+=b-a;        }    }    for(int i=1;i<=maxn;i++){        if(cs[i]==0){            final=(final+((1<<(i-1))*cnt[i][1]))%idy;        }else{            final=(final+((1<<(i-1))*cnt[i][0]))%idy;        }    }    printf("%lld\n",final);}int main(){    long long temp=1;m[temp]=1;    for(long long i=1;i<=62;i++){        m[temp*2]=i+1;        temp*=2;        int te=m[temp];    }    scanf("%d",&T);    while(T--){        scanf("%d%d%d",&a,&b,&c);a=a-1;        init();        solve();    }    return 0;}

最后一道题等我会了再回来填坑吧,回寝室洗澡了,再吐槽一句,学校里没有超市,买东西还得打电话给外面的超市,结果要买的东西都没有,伤心…