2019年4月博客汇总
[信息课D2]加密解密
蒟蒻对象丢了,于是去听了信息课
拿C++写了一个DD加密软件
代码
#include<cstdio>
#include<cstdlib>
using namespace std;
namespace orz{
const int N=19260817;
char s[N];
char name[N];
char dd[N];
int QAQ(){
char t;
printf("输入0以加密,1以解密\n");
int T;
scanf("%d",&T);
switch(T){
case 0:
printf("请输入加密文件地址\n");
scanf(" %s",s);
printf("请输入加密密钥\n");
int orz;
scanf("%d",&orz);
srand(orz);
printf("请输入加密后文件地址\n");
scanf(" %s",name);
freopen(s,"r",stdin);
freopen(name,"w",stdout);
do{
t=getchar();
putchar(t-rand()%23);
}while(t!=EOF);
break;
case 1:
printf("请输入解密文件地址\n");
scanf(" %s",s);
printf("请输入解压密钥\n");
int Orz;
scanf("%d",&Orz);
srand(Orz);
printf("请输入解密后文件地址\n");
scanf(" %s",name);
freopen(s,"r",stdin);
freopen(name,"w",stdout);
do{
t=getchar();
putchar(t+rand()%23);
}while(t!=EOF);
break;
}
return false;
}
}
int main(){
return orz::QAQ();
}
[SXOI2019]游记
这次省选是作为正式选手的最后一名去考的,最后也差不多考了最后一名。
本来就是来水的也无所谓,不过有一些失误真的可惜。
Day1
T1
暴力水了60分,后来还搞了半天trie树,考后知道是可持久化01trie后推了推也搞出正解了。有点可惜,不过毕竟没怎么写过可持久化数据结构,知道正解也不一定能写出来。
T2
语文太差没怎么读懂题,以为是字符串就直接跳过了,知道是图论我才追悔莫及,不过也水不了多少分。
T3
他改变了传统题
搞了半天骗了4分,第二个点就是爆long long 调不对。
Day2
T1
计数背包加玄学优化,计数不能Orz。
T2
想到贪心策略没推广,后来发现挺显然的,最近打算去学一下长链剖分。
退火出奇迹!!
T3
这题没看懂
希望明年还能再来考吧
给DKY大佬跪了
[模版]主席树
抄题解的主席树板子Orz
思路
维护一个值域主席树,从左往右扫这个数组,每次将扫到的数加入主席树中。显然一个区间某个值域数字出现的次数就是区间右端点的历史版本减去区间左端点的历史版本,于是在两个历史版本上二分即可。
这个题启示我们如果一个东西可以后减前搞出来可以考虑下主席树。
代码
#include<cstdio>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
namespace orz{
const int N=2500000,M=10000010;
inline int read(){
int a=1,b=0;char t;
do{t=getchar();if(t=='-')a=-1;}while(t>'9'||t<'0');
do{b=b*10-'0'+t;t=getchar();}while(t>='0'&&t<='9');
return a*b;
}
struct ndoe{
int sum,leftChild,rightChild;
}t[M];
int n,q,m,cnt;
int a[N],b[N];
int root[N];
int build(int l,int r){
int p=++cnt;
t[p].sum=0;
if(l<r){
t[p].leftChild=build(l,mid);
t[p].rightChild=build(mid+1,r);
}
return p;
}
inline int update(int pre,int l,int r,int x){
int p=++cnt;
t[p].leftChild=t[pre].leftChild;
t[p].rightChild=t[pre].rightChild;
t[p].sum=t[pre].sum+1;
if(l<r){
if(x<=mid)t[p].leftChild=update(t[pre].leftChild,l,mid,x);
else t[p].rightChild=update(t[pre].rightChild,mid+1,r,x);
}
return p;
}
inline int query(int x,int y,int l,int r,int k){
if(l==r)return l;
int d=t[t[y].leftChild].sum-t[t[x].leftChild].sum;
if(d>=k)return query(t[x].leftChild,t[y].leftChild,l,mid,k);
else return query(t[x].rightChild,t[y].rightChild,mid+1,r,k-d);
}
int QAQ(){
n=read();q=read();
for(int i=1;i<=n;++i){
b[i]=a[i]=read();
}
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-b-1;
root[0]=build(1,m);
for(int i=1;i<=n;++i){
int d=lower_bound(b+1,b+1+m,a[i])-b;
root[i]=update(root[i-1],1,m,d);
}
register int x,y,z;
while(q--){
x=read(),y=read(),z=read();
int d=query(root[x-1],root[y],1,m,z);
printf("%d\n",b[d]);
}
return false;
}
}
int main(){
return orz::QAQ();
}
[HAOI2014]贴海报
线段树题就是不用线段树x1
这题寒假讲的是线段树加离散化维护区间的做法。但是那样太麻烦。
当我们看到区间改为同一个值时我们想到了什么?是珂朵莉!!!
考虑这个题,由于不同的颜色数量不会超过m。所以珂朵莉的时间复杂度最差为\(O(mlogm)\)。
一般情况下远远无法到这个复杂度,而且珂朵莉的常数要比线段树小,所以线段树就被吊打了。
代码
#include<cstdio>
#include<cstdio>
#include<set>
#include<algorithm>
#include<vector>
#define IT set<node>::iterator
using namespace std;
namespace orz{
const int M=10000;
bool v[M];
struct node{
int l,r;
mutable int value;
node(int L,int R,int V){
l=L;r=R;value=V;
}
node(const int &pos){
r=-1;value=0;l=pos;
}
bool operator < (const node &a)const {
return l<a.l;
}
};
inline int read(){
int a=1,b=0;char t;
do{t=getchar();if(t=='-')a=-1;}while(t>'9'||t<'0');
do{b=b*10-'0'+t;t=getchar();}while(t>='0'&&t<='9');
return a*b;
}
set<node>s;
inline IT split(int pos){
IT it=s.lower_bound(node(pos));
if(it!=s.end()&&it->l==pos)
return it;
--it;
int l=it->l,r=it->r;
int v=it->value;
s.erase(it);
s.insert(node(l,pos-1,v));
return s.insert(node(pos,r,v)).first;
}
inline void assign_val(int l,int r,int val){
IT itr=split(r+1),itl=split(l);
s.erase(itl,itr);
s.insert(node(l,r,val));
}
int QAQ(){
int n,m,x,y,ans=0;
n=read();m=read();
s.insert(node(1,n,0));
for(int i=1;i<=m;++i){
x=read();y=read();
assign_val(x,y,i);
}
for(IT i=s.begin();i!=s.end();++i){
ans+=(i->value)?(v[i->value]?0:1):0;
v[i->value]=true;
}
printf("%d",ans);
return false;
}
}
int main(){
return orz::QAQ();
}
[CQOI2006]简单题
线段树题就是不用线段树x2
由于反转两次后就会变回去,所以用差分树状数组维护改变了几次就可以了。
代码
#include<cstdio>
using namespace std;
namespace orz{
const int N=500000;
int c[N];
int n,m;
inline int read(){
int a=1,b=0;char t;
do{t=getchar();if(t=='-')a=-1;}while(t>'9'||t<'0');
do{b=b*10-'0'+t;t=getchar();}while(t>='0'&&t<='9');
return a*b;
}
inline void add(int x){
for(;x<=n;x+=(x&-x))c[x]+=1;
}
inline int ask(int x){
int ans=0;
for(;x;x-=(x&-x))ans+=c[x];
return ans;
}
int QAQ(){
n=read();m=read();
while(m--){
switch(read()){
case 1:
add(read());add(read()+1);
break;
case 2:
printf(ask(read())&1?"1\n":"0\n");
break;
}
}
return false;
}
}
int main(){
return orz::QAQ();
}
[JSOI2008]最大数
线段树题就是不用线段树x3
因为每一回查询都是从后往前查,所以明显如果后面的数更大的话前面的较小的数就没用了。
于是维护一个单调递减的单调栈,在下标上二分就可以了。
代码
#include<cstdio>
using namespace std;
namespace orz{
const int N=201000;
struct node{
int pos;
long long value;
}s[N];
int top=0;
int n=1;
long long MOD;
inline long long read(){
long long a=1,b=0;char t;
do{t=getchar();if(t=='-')a=-1;}while(t>'9'||t<'0');
do{b=b*10-'0'+t;t=getchar();}while(t>='0'&&t<='9');
return a*b;
}
inline int getOrder(){
char t;
do{t=getchar();}while(t^'A'&&t^'Q');
return t^'A'?2:1;
}
inline long long ask(int x){
int pos=n-x;
int l=1,r=top,mid;
while(l<r){
mid=(l+r)>>1;
if(s[mid].pos<pos)l=mid+1;
else r=mid;
}
return s[l].value;
}
inline void add(int x){
while(s[top].value<x&&top)
--top;
s[++top].value=x;
s[top].pos=n++;
}
int QAQ(){
int m;
long long t=0;
m=read();
MOD=read();
while(m--){
switch(getOrder()){
case 1:
add((read()+t)%MOD);
break;
case 2:
printf("%lld\n",t=ask(read()));
break;
}
}
return false;
}
}
int main(){
return orz::QAQ();
}