Typesetting math: 100%

Luvwgyx的娱乐场-题解

题解不按顺序给出

目录:

ycz的妹子

题目背景:
yczycz有很多很多的妹子(yczycz:瞎说)

题目描述:
机房神犇yczycz有n个青梅竹马,她们分别住在1~n号城市中。小时候的她们美丽可爱,但是由于女大十八变,有些妹子的颜值发生了变化,但是十分重感情的yczycz神犇不忍心抛弃她们,于是记录下来了她们颜值变化的值,我们用CxyCxy表示第xx个城市的妹子的颜值下降了yyyy有可能是负数)。长大之后的yczycz非常有魅力,有许多妹子被yczycz迷得神魂颠倒,我们用IxyIxy表示第xx个城市有一个妹子喜欢上了yczycz,她的颜值为yyyy有可能是负数,但是yczycz来者不拒)。但在中途有一些妹子和yczycz吵架了,于是就分手了,我们用DxDx表示第xx个妹子和yczycz分手了。

最近神犇yczycz要去全国各地找他的妹子们,为了方便计算,我们珂以把yczycz的妹子所在的城市当作是一条直线,并且挨在一起。神犇yczycz由于忙于和他的妹子们联系此时已经很累了,于是交给你一个这样的任务:他想知道他在某个时间去找他的所有妹子们珂以获得多大的愉悦度,这个愉悦度为他找的妹子的颜值数,你要做的就是求出这个愉悦度之和(注意长大后妹子们的颜值可能为负数/滑稽)。

注意:每个城市只允许有一个妹子,也就是说后来喜欢上yczycz的妹子会赶走之前这个城市喜欢yczycz的妹子(一城不容二女)

输入格式:
第一行两个正整数nnmm (1<=n<=100000)(1<=n<=100000)

第二行为nn个整数aiai,表示小时候yczycz的青梅竹马的颜值(1<=ai<=109)(1<=ai<=109)

接下来mm行,每行为一条信息,每条信息可能是下面的一种:

CxyCxy表示第xx个城市的妹子的颜值下降了yy

IxyIxy表示在第xx个城市有一个颜值为yy的妹子迷上了yczycz

DxDx表示第xx个妹子和yczycz分手了

QQ表示yczycz现在想知道如果现在去找他所有的妹子们珂以获得多大的愉悦度

说明:妹子们居住的城市编号最大为5×1055×105

输出格式:
对于每一个QQ输出一个整数

样例输入:

5 10
1 2 3 4 5
Q
C 3 2
Q
I 6 6
Q
D 4
Q
C 4 2
I 7 9
Q

样例输出:

15
13
19
15
22

提示与说明:
对于30%的数据1<=n,m<=101<=n,m<=10

对于70%的数据1<=n,m<=10001<=n,m<=1000

对于100%的数据1<=n,m<=100000,1<=ai,y<=1091<=n,m<=100000,1<=ai,y<=109

题解:

30分:我也不知道怎么拿啊...(暴力分xiajb给的)

70分:直接暴力就好了...

code:点此跳过此代码

/*Program from Luvwgyx*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
int n,m,a[maxn];char s[10];
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=m;i++){
        scanf("%s",s+1);
        if(s[1]=='C'){
            int x=read(),y=read();
            a[x]-=y;
        }
        if(s[1]=='I'){
            int x=read(),y=read();
            a[x]=y;
        }
        if(s[1]=='D'){
            int cnt=0,pos,x=read();
            for(int i=1;i<=maxn-10;i++)
                if(a[i]){cnt++;if(cnt==x){pos=i;break;}}
            a[pos]=0;
        }
        if(s[1]=='Q'){
            int ans=0;
            for(int i=1;i<=maxn-10;i++)
                ans+=a[i];
            printf("%d\n",ans);
        }
    }
    return 0;
}

100分:

线段树中存颜值和以及妹子的数量就好了,具体的代码去看。

PS:应Wolfycz墙裂要求,此处贴上他的代码(好丑啊)我代码在下面,泥萌觉得哪个好看就看哪个吧QAQ

code:点此跳过此代码

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x>=10)	print(x/10);
    putchar(x%10+'0');
}
const int N=1e5;
int val[(N<<1)+10];
struct Segment{
    #define ls (p<<1)
    #define rs (p<<1|1)
    struct node{
        int cnt;ll sum;
        void insert(int _sum,int _cnt){sum=_sum,cnt=_cnt;}
        node(){sum=cnt=0;}
    }tree[(N<<3)+10];
    friend node operator +(const node &x,const node &y){
        node z;
        z.sum=x.sum+y.sum;
        z.cnt=x.cnt+y.cnt;
        return z;
    }
    void build(int p,int l,int r){
        if (l==r){
            tree[p].insert(val[l],(bool)val[l]);
            return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid),build(rs,mid+1,r);
        tree[p]=tree[ls]+tree[rs];
    }
    void change(int p,int l,int r,int x,int v){
        if (l==r){
            tree[p].insert(v,1);
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid)	change(ls,l,mid,x,v);
        else	change(rs,mid+1,r,x,v);
        tree[p]=tree[ls]+tree[rs];
    }
    void insert(int p,int l,int r,int x,int v){
        if (l==r){
            tree[p].sum-=v;
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid)	insert(ls,l,mid,x,v);
        else	insert(rs,mid+1,r,x,v);
        tree[p]=tree[ls]+tree[rs];
    }
    void Delete(int p,int l,int r,int x){
        if (l==r){
            tree[p].insert(0,0);
            return;
        }
        int mid=(l+r)>>1;
        if (x<=tree[ls].cnt)	Delete(ls,l,mid,x);
        else	Delete(rs,mid+1,r,x-tree[ls].cnt);
        tree[p]=tree[ls]+tree[rs];
    }
}Tree;
char s[2];
int main(){
    int n=read(),m=read();
    for (int i=1;i<=n;i++)	val[i]=read();
    Tree.build(1,1,N<<1);
    for (int i=1;i<=m;i++){
        scanf("%s",s);
        if (s[0]=='C'){
            int x=read(),y=read();
            Tree.insert(1,1,N<<1,x,y);
        }
        if (s[0]=='I'){
            int x=read(),y=read();
            Tree.change(1,1,N<<1,x,y);
        }
        if (s[0]=='D'){
            int x=read();
            Tree.Delete(1,1,N<<1,x);
        }
        if (s[0]=='Q')	printf("%lld\n",Tree.tree[1].sum);
    }
    return 0;
}
/*Program from Luvwgyx*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn=2e5+10;
ll n,m,a[maxn];char s[10];
struct node{ll cnt,sum;}tree[maxn<<2];
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void update(ll k){
    tree[k].cnt=tree[k<<1].cnt+tree[k<<1|1].cnt;
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
    return;
}
void build(ll k,ll l,ll r){
    if(l==r){
        tree[k].sum=a[l];
        if(a[l]!=0)tree[k].cnt++;
        return ;
    }
    ll mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    update(k);
}
void change(ll k,ll l,ll r,ll x,ll y){
    if(l==r){tree[k].sum-=y;/*prllf("\n%d\n",l);*/return ;}
    ll mid=(l+r)>>1;
    if(x<=mid)change(k<<1,l,mid,x,y);
    else change(k<<1|1,mid+1,r,x,y);
    update(k);
}
void add(ll k,ll l,ll r,ll x,ll y){
    if(l==r){tree[k].sum=y;tree[k].cnt=1;/*prllf("\n%d\n",l);*/return ;}
    ll mid=(l+r)>>1;
    if(x<=mid)add(k<<1,l,mid,x,y);
    else add(k<<1|1,mid+1,r,x,y);
    update(k);
}
void del(ll k,ll l,ll r,ll x){
    if(l>r)return ;//prllf("%d %d\n",l,r);
    if(l==r&&x==tree[k].cnt){tree[k].sum=0;tree[k].cnt--;return ;}
    ll mid=(l+r)>>1;//prllf("%d\n",tree[k<<1].cnt);
    if(x<=tree[k<<1].cnt)del(k<<1,l,mid,x);
    else del(k<<1|1,mid+1,r,x-tree[k<<1].cnt);
    update(k);
}
/*
void dfs(ll k,ll l,ll r){
    if(l==r){if(tree[k].sum!=0)prllf("%d:%d ",l,tree[k].sum);return ;}
    ll mid=(l+r)>>1;
    dfs(k<<1,l,mid);dfs(k<<1|1,mid+1,r);
}
*/
int main(){
    //freopen("girl10.in","r",stdin);
    //freopen("girl10.out","w",stdout);
    n=read();m=read();
    for(ll i=1;i<=n;i++)a[i]=read();
    build(1,1,maxn-10);
    while(m--){
        scanf("%s",s);
        if(s[0]=='C'){ll x=read(),y=read();change(1,1,maxn-10,x,y);}
        if(s[0]=='I'){ll x=read(),y=read();add(1,1,maxn-10,x,y);}
        if(s[0]=='D'){ll x=read();del(1,1,maxn-10,x);}
        if(s[0]=='Q')printf("%lld\n",tree[1].sum);
        //dfs(1,1,maxn-10);puts("");
    }
    return 0;
}
/*
2 11
18 4
C 2 -1
C 1 0
I 19 -17
I 8 -1
D 3
I 19 12
Q
D 1
C 2 -2
D 2
Q
*/

lty loves 96!

题目背景:
众所周知,ltylty非常喜欢9696这两个数字(想歪的现在马上面壁去),更甚于复读(人本复)

题目描述:
由于爱屋及乌,因此,ltylty对于那些含有9696的数也非常喜欢,而这里的含有不是一般的含有,而是具有以下性质的含有(三条都需要满足):

  • 这个数为一个NN位数,且没有前置零
  • 这个数中至少要出现MM9966(例:986996986996中出现了55次,99出现了33次,66出现了22次,共计55次)
  • 这个数存在任意连续的三位AA,BB,CC,满足下面任意一条
    • A+B+CA+B+C9966
    • (A2+B2)(A2+B2)%CC9966,如果CC00,则该条件视为不满足

输入格式:
一行,两个数NN,MM

输出格式:
一个数,表示这样的数的个数。

样例输入:

3 1

样例输出:

452

提示与说明:
对于10%的数据,N<=6N<=6

对于40%的数据,N<=18N<=18

对于100%的数据,N<=50N<=500<=M<=N0<=M<=N

题解:

很简单的一道数位dp。

记录f[i][a][b][j][k](a,b9;i,jN;k=0 or 1)f[i][a][b][j][k](a,b9;i,jN;k=0 or 1),表示一个ii位数,第ii位和第i1i1位分别为a,ba,b,这个数中有jj个6和9,这个数是否出现过题目中描述的两个条件,有则k=1k=1,没有则k=0k=0

转移:

a,b,ca,b,c不满足题目中条件时:

f[i][a][b][j][0]+=f[i1][b][c][jlast][0],f[i][a][b][j][1]+=f[i1][b][c][jlast][1]f[i][a][b][j][0]+=f[i1][b][c][jlast][0],f[i][a][b][j][1]+=f[i1][b][c][jlast][1]

否则

f[i][a][b][j][1]+=f[i1][b][c][jlast][0]+f[i1][b][c][jlast][1]f[i][a][b][j][1]+=f[i1][b][c][jlast][0]+f[i1][b][c][jlast][1]

ff数组的类型?

如果你开intint类型,你可以获得1010分的好成绩。

如果你开longlonglonglong类型,你可以获得4040分的好成绩。

如果你开普通的未压位高精度类型,你可以获得00的好成绩。

如果你使用任意压位高精度类型,你可以获得100100分的好成绩。

emmmm,好像有dalaodalaoint128int128水了85pts85pts来着....

code:点此跳过此代码

/*Program from wym*/
#include<bits/stdc++.h>
const int maxn=50;
const int digit=9;
const int base=1000000000;
struct bignum{
	int v[maxn/digit+2];
	int clear(){
		memset(v,0,sizeof v);
		return 0;
	}
	int print()	{
		printf("%d",v[v[0]]);
		for(int i=v[0]-1; i>0; --i){
			int k=1;
			for(int j=1; j<digit; ++j){
				k*=10;
				if(v[i]<k)putchar('0');
			}printf("%d",v[i]);
		}
		puts("");
		return 0;
	}
};
bignum operator +(bignum a,bignum b){
	bignum ans;	ans.clear();
	ans.v[0]=std::max(a.v[0],b.v[0]);
	int r=0;
	for(int i=1; i<=ans.v[0]; ++i){
		ans.v[i]=a.v[i]+b.v[i]+r;
		r=ans.v[i]/base;
		ans.v[i]%=base;
	}
	if(r!=0)ans.v[++ans.v[0]]=r;
	return ans;
}
bignum operator +=(bignum &a,bignum b){
	a=a+b;
	return a;
}
bignum f[maxn+1][10][10][maxn+1][2],ans;
int n,m;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0; i<=n; ++i)
		for(int a=0; a<=9; ++a)
			for(int b=0; b<=9; ++b)
				for(int j=0; j<=n; ++j){
					f[i][a][b][j][0].clear();
					f[i][a][b][j][1].clear();
				}
	f[0][0][0][0][0].v[0]=1;
	f[0][0][0][0][0].v[1]=1;
	for(int i=1; i<=n; ++i)
		for(int a=0; a<=9; ++a)
			for(int b=0; b<=9; ++b)
				for(int j=0; j<=i; ++j)
					for(int c=0; c<=9; ++c){
						int last_j=j-(((a==6)||(a==9))?1:0);
						if((last_j<0)||(last_j>=i))continue;
						if((i>=3)&&(((a+b+c==9)||(a+b+c==6))||((c!=0)&&(((a*a+b*b)%c==9)||((a*a+b*b)%c==6)))))
							f[i][a][b][j][1]+=f[i-1][b][c][last_j][0]+f[i-1][b][c][last_j][1];
						else {
							f[i][a][b][j][0]+=f[i-1][b][c][last_j][0];
							f[i][a][b][j][1]+=f[i-1][b][c][last_j][1];
						}
					}
	ans.clear();
	for(int i=1; i<=9; ++i)
		for(int j=0; j<=9; ++j)
			for(int k=m; k<=n; ++k)
				ans+=f[n][i][j][k][1];
	ans.print();
	return 0;
}

mzf的考验

题目背景:
mzfmzf立志要成为一个豪杰,当然,他也是一个OIerOIer
他希望自己除了会OIOI之外还会各种东西,比如心理学、吉他、把妹等等。
为了让自己有更大的魅力,他不驼背,不熬夜,整天锻炼,双目炯炯有神,是我们机房最不像OIerOIer的人。
然而,在与我们格格不入若干天并且将《易经》研究透彻之后,承受不住我们对他另类的言论,他爆发了。
机房在那一刹那仿佛天塌地陷,世界末日。

题目描述:
八卦有乾、坤、震、巽、坎、离、艮、兑;
两两组合,一上一下,形成了六十四卦,每卦六爻,一共三百八十四爻。
爻分阴阳,阳爻性属阳刚,阴爻性属阴柔。天下之大,无奇不有。千奇百怪,皆出此处。
mzfmzf研究透彻了易经之后,画出了nn个奇怪的图案。他说那是他改进出来的更强大的卜卦体系。
每一个图案有二十行,每一行要么是阴爻(0)(0),要么是阳爻(1)(1),作为一个OIerOIer,我们可以将卦象看成一个个二进制串;
他将nn个图案画在了符纸上,然后进行mm次操作:

操作1:翻转区间[l,r][l,r]的图案,比如(3,1,2,5)(3,1,2,5)变成(5,2,1,3)(5,2,1,3)

操作2:mzfmzf画地为卦,将[l,r][l,r]之间的卦象都异或上新画的那个卦象;

操作3:mzfmzf会询问机房里的其他人[l,r][l,r]之间卦象代表的二进制数权值和。

如果不能正确回答每个操作33,那么机房风水格局将会改变,我们都将...!

由于mzfmzf疯狂之下将我们都捆♂绑♂了起来,所以只能求求你来帮我们解决这个问题。

输入格式:
第一行两个正整数:nnmmnn为序列长度,mm为操作个数)

第二行nn个正整数:a[i]a[i] (用1010进制数表示每个卦象)(1<=i<=n)(1<=i<=n)

接下来mm行:每行首先一个正整数optopt表示操作类型

  1. opt==1opt==1:两个正整数:llrr。请翻转区间[l,r][l,r]
  2. opt==2opt==2:三个正整数:llrrdd。请将区间[l,r][l,r]中的所有卦象都异或卦象dd(0<=d<=105)(0<=d<=105)
  3. opt==3opt==3:两个正整数:llrr。请查询区间[l,r][l,r]的卦象权值和。

输出格式:
对于每个 opt==3opt==3 的情况,输出一行答案。

样例输入:

8 9
4 6 2 1 7 9 10 2
1 1 4
3 1 6
2 4 5 2
3 1 6
2 1 5 8
3 1 6
2 5 7 10
3 4 7
3 1 10

样例输出:

29
29
69
24
59

提示与说明:
对于20%的数据,n<=1000n<=1000m<=1000m<=1000

对于另外20%的数据,不存在操作11

对于另外20%的数据,保证nn22的次幂,且在操作11中,保证l=i×(2j)+1,r=(i+1)×(2j)l=i×(2j)+1,r=(i+1)×(2j),其中iijj为任意值

对于100%的数据,n<=105n<=105m<=5×104m<=5×1041<=l<=r<=n1<=l<=r<=n0<=d<2200<=d<220

题解:
方法一:

暴力模拟,期望得分:20。

code:点此跳过此代码

/*Program from Luvwgyx*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1010;
int n,m,a[maxn],b[maxn];
int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=m;i++){
		int opt=read(),l=read(),r=read(),d;
		if(opt==1){
			for(int i=l;i<=r;i++)b[i]=a[i];
			for(int i=r;i>=l;i--)a[i]=b[l+r-i];
			memset(b,0,sizeof(0));
			
		}else if(opt==2){
			d=read();
			for(int i=l;i<=r;i++)a[i]^=d;
		}else if(opt==3){
			ll ret=0;
			for(int i=l;i<=r;i++)ret+=a[i];
			printf("%lld\n",ret);
		}
	}
	return 0;
}

方法二:

不存在操作1,那我们可以考虑用线段树来做。

普通的线段树:期望得分:20。

结合暴力,期望得分:40。

代码就不放了,自己去写一写吧

方法三:
有翻转操作了,但是这个反转的区间有限制,我们会发现这个区间其实就是线段树上的区间的左右端点,我们只需要找到这个区间,然后翻转就好了。

线段树+拆位异或...期望得分:40分

结合暴力,期望得分:60分

线段树内维护权值和以及二进制下数位的值,然后拆位异或,注意一下标记下传之类的就好了。

都是板子,直接上代码看吧...

code:点此跳过此代码

/*Program from lichenxi*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mid ((s[x].l+s[x].r)>>1)
#define size (s[x].r-s[x].l+1)
int n,m,opt,x,y,c[21],ans[21],f[21];
long long d[300001],z,sum,w[21],a[300001];
struct oo{int l,r,rev,t[21],ls,rs;long long _XOR;}s[1200001];
int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void gettwo(int *a,long long v)
{
    int now=0;
    while(v)
    {
        if(v&1)a[now]=1;
        v>>=1;now++;
    }
}
void update(int x){for(int i=0;i<20;i++)s[x].t[i]=s[s[x].ls].t[i]+s[s[x].rs].t[i];}
void build(int x,int l,int r)
{
    s[x].l=l,s[x].r=r;
    if(l==r){gettwo(s[x].t,d[l]);return ;}
    s[x].ls=x<<1,s[x].rs=x<<1|1;
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    update(x);
}
void pushrev(int x)
{
    int ca=s[s[x].ls].r-s[s[x].ls].l,ka=s[s[x].rs].r-s[s[x].rs].l;
    s[s[x].ls].l=s[x].l;s[s[x].ls].r=s[s[x].ls].l+ca;
    s[s[x].rs].l=s[s[x].ls].r+1;s[s[x].rs].r=s[s[x].rs].l+ka;
}
void pushdown_rev(int x)
{
    s[s[x].ls].rev^=1,s[s[x].rs].rev^=1,s[x].rev^=1;
    swap(s[x].ls,s[x].rs);
    pushrev(x);
}
void push_XOR(int *c,int x){for(int i=0;i<20;i++)if(c[i])s[x].t[i]=size-s[x].t[i];}
void pushdown_XOR(int x)
{
    s[s[x].ls]._XOR^=s[x]._XOR;s[s[x].rs]._XOR^=s[x]._XOR;
    for(int i=0;i<20;i++)f[i]=0;gettwo(f,s[x]._XOR);
    push_XOR(f,s[x].ls);push_XOR(f,s[x].rs);
    s[x]._XOR=0;
}
void putrev(int x,int l,int r)
{
    pushrev(x);
    if(s[x].rev)pushdown_rev(x);
    if(s[x]._XOR)pushdown_XOR(x);
    if(s[x].l==l&&s[x].r==r)
    {
        swap(s[x].ls,s[x].rs);
        s[s[x].ls].rev^=1;s[s[x].rs].rev^=1;
        int ca=s[s[x].ls].r-s[s[x].ls].l,ka=s[s[x].rs].r-s[s[x].rs].l;
        s[s[x].ls].l=s[x].l;s[s[x].ls].r=s[s[x].ls].l+ca;
        s[s[x].rs].l=s[s[x].ls].r+1;s[s[x].rs].r=s[s[x].rs].l+ka;
        return ;
    }
    if(l<=mid)putrev(s[x].ls,l,r);
    if(r>mid)putrev(s[x].rs,l,r);
    update(x);
}
void change(int x,int l,int r,long long d)
{
    pushrev(x);
    if(s[x].rev)pushdown_rev(x);
    if(s[x]._XOR)pushdown_XOR(x);
    if(l<=s[x].l&&r>=s[x].r){push_XOR(c,x),s[x]._XOR^=d;return ;}
    if(l<=mid)change(s[x].ls,l,r,d);
    if(r>mid)change(s[x].rs,l,r,d);
    update(x);
}
void get(int x,int l,int r)
{
    pushrev(x);
    if(s[x].rev)pushdown_rev(x);
    if(s[x]._XOR)pushdown_XOR(x);
    if(l<=s[x].l&&r>=s[x].r)
    {
        for(int i=0;i<20;i++)ans[i]+=s[x].t[i];
        return ;
    }
    if(l<=mid)get(s[x].ls,l,r);
    if(r>mid)get(s[x].rs,l,r);
    update(x);
}
int main()
{
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
    w[0]=1;
    for(int i=1;i<22;i++)w[i]=w[i-1]<<1;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld",&d[i]);
	if(n<=1000&&m<=1000){
		while(m--){
			int opt=read(),l=read(),r=read(),x;
			if(opt==1){
				for(int i=l;i<=r;i++)a[i]=d[i];
				for(int i=r;i>=l;i--)d[i]=a[l+r-i];
				memset(a,0,sizeof(a));
			}else if(opt==2){
				x=read();
				for(int i=l;i<=r;i++)d[i]^=x;
			}else if(opt==3){
				long long ret=0;
				for(int i=l;i<=r;i++)ret+=d[i];
				printf("%lld\n",ret);
			}
		}
		return 0;
	}
    build(1,1,n);
    while(m--)
    {
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==1)putrev(1,x,y);
        if(opt==2)
        {
            scanf("%lld",&z);
            for(int i=0;i<20;i++)c[i]=0;
            gettwo(c,z);change(1,x,y,z);
        }
        if(opt==3)
        {
            for(int i=0;i<20;i++)ans[i]=0;get(1,x,y);
            sum=0;for(int i=0;i<20;i++)sum+=ans[i]*w[i];
            printf("%lld\n",sum);
        }
    }
}

方法四:

当操作11没有限制后,我们可以想到用平衡树,开2020棵平衡树就可以TLETLE了(常数小的说不定卡的过)。每次翻转的时候我们需要翻转2020棵平衡树,这样非常不优。那么我们就把每个数的二进制存到平衡树的节点上,每次异或的时候再拿出来用,翻转操作也只要做一次就好。理论时间复杂度O(20 m logn)O(20 m logn),常数小的基本上可以过

至于有dalaodalao写的是splaysplay55556060啥的我也不知道啥情况啊....

我真的没有想卡常啊...可能是我的splaysplay常数比较小吧...说不定用fhq treapfhq treap常数小一些,但是我不会写

期望得分:100分。

code:点此跳过此代码

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x>=10)	print(x/10);
    putchar(x%10+'0');
}
const int N=5e5;
int v[N+10],g[20]; 
void Extract(int x,int *cnt){for (int i=0;i<20;i++)	cnt[i]=x&1,x>>=1;}
struct Splay{
    #define ls(x) tree[x][0]
    #define rs(x) tree[x][1]
    #define T(x) (rs(f[x])==x)
    ll sum[N+10];
    int tree[N+10][2],f[N+10],size[N+10],cnt[N+10][20],Xor[N+10],val[N+10],A[20];
    bool rev[N+10];
    int root,len;
    void updata(int x){
        size[x]=size[ls(x)]+size[rs(x)]+1;
        sum[x]=sum[ls(x)]+sum[rs(x)]+val[x];
        for (int i=0;i<20;i++)	cnt[x][i]=cnt[ls(x)][i]+cnt[rs(x)][i]+((val[x]>>i)&1);
    }
    void move(int x){
        int fa=f[x],son=tree[x][T(x)^1];
        tree[x][T(x)^1]=fa;
        tree[fa][T(x)]=son;
        if (son)	f[son]=fa;
        f[x]=f[fa];
        if (f[x])	tree[f[x]][T(fa)]=x;
        f[fa]=x;
        updata(fa),updata(x);
    }
    void splay(int x){
        while (f[x]){
            if (f[f[x]])	T(f[x])==T(x)?move(f[x]):move(x);
            move(x);
        }
        root=x;
    }
    void Add_rev(int x){
        if (!x)	return;
        swap(ls(x),rs(x));
        rev[x]^=1;
    }
    void Add_xor(int x,int v){
        if (!x)	return;
        Extract(v,A);
        ll res=0;
        for (int i=0;i<20;i++){
            if (A[i])	cnt[x][i]=size[x]-cnt[x][i];
            res+=1ll*cnt[x][i]*g[i];
        }
        sum[x]=res;
        val[x]^=v,Xor[x]^=v;
    }
    void pushdown(int x){
        if (rev[x]){
            Add_rev(ls(x));
            Add_rev(rs(x));
            rev[x]=0;
        }
        if (Xor[x]){
            Add_xor(ls(x),Xor[x]);
            Add_xor(rs(x),Xor[x]);
            Xor[x]=0;
        }
    }
    int find(int x,int i){
        pushdown(i);
        if (size[ls(i)]+1==x)	return i;
        if (x<=size[ls(i)])	return find(x,ls(i));
        return find(x-size[ls(i)]-1,rs(i));
    }
    void reverse(int l,int r){
        int x=find(l,root),y=find(r+2,root);
        splay(x),splay(y);
        if (f[x]!=root)	move(x);
        Add_rev(rs(x));
//		updata(x),updata(y);
    }
    void _xor(int l,int r,int v){
        int x=find(l,root),y=find(r+2,root);
        splay(x),splay(y);
        if (f[x]!=root)	move(x);
        Add_xor(rs(x),v);
        updata(x),updata(y);
    }
    ll Query(int l,int r){
        int x=find(l,root),y=find(r+2,root);
        splay(x),splay(y);
        if (f[x]!=root)	move(x);
        return sum[rs(x)];
    }
    void build(int fa,int l,int r,int &x){
        if (l>r)	return;
        int mid=(l+r)>>1;
        x=++len,f[x]=fa,val[x]=v[mid];
        if (l==r){
            size[x]=1,sum[x]=val[x];
            Extract(val[x],cnt[x]);
            return;
        }
        build(x,l,mid-1,ls(x));
        build(x,mid+1,r,rs(x));
        updata(x);
    }
    void init(int n){
        len=2,root=1;
        rs(1)=size[1]=2,f[2]=size[2]=1;
        build(2,1,n,ls(2));
        updata(2),updata(1);
    }
}Tree;
int main(){
    g[0]=1;
    for (int i=1;i<20;i++)	g[i]=g[i-1]<<1;
    int n=read(),m=read();
    for (int i=1;i<=n;i++)	v[i]=read();
    Tree.init(n);
    for (int i=1;i<=m;i++){
        int type=read(),l=read(),r=read();
        if (type==1)	Tree.reverse(l,r);
        if (type==2)	Tree._xor(l,r,read());
        if (type==3)	printf("%lld\n",Tree.Query(l,r));
    }
    return 0;
}

hby与tkw的基情

题目背景:

基情恒久远,一对永流传。

hbyhbytkwtkw是一对好基友,他们经常在一起做♂游♂戏 (/滑稽)。

题目描述:
他们喜欢玩字符串游戏,尤其喜欢玩回文串。每次hbyhby会给出一个数nn,那么tkwtkw就需要给出Ans=ni=1i×s[i]×[i%2]Ans=ni=1i×s[i]×[i%2]
其中s[i]s[i]代表长度为ii的数字回文串的个数,最后面是boolbool表达式

不过由于tkwtkw最近学yczycz找妹纸去了,于是他就将这个问题交给了你,如果你不能在1s1s内答出来,那么hbyhbytkwtkw的基情将会破裂!(不过那样tkw就可以安心地找妹纸了)

由于答案会非常大,所以你只需要输出答案%109+7%109+7的值即可

输入格式:
第一行一个整数TT
接下来TT行,每行一个数nn

输出格式:
TT行,每行代表一个答案

样例输入:

2
1
3

样例输出:

26
2054

提示与说明:
对于10%的数据:n<=5n<=5

对于另外20%的数据:n<=107n<=107

对于另外20%的数据:T=1T=1

对于100%的数据:T<=5×105,n<=109T<=5×105,n<=109

题解:

10%:随便玩玩就好

30%:发现:s[i]=s[i2]26s[i]=s[i2]26s[1]=26s[1]=26,递推即可

50%:由于只有一组数据,可以用矩阵快速幂优化以上的递推。

100%:开了O2O2说不定矩阵快速幂就过了。。。
然后我们要求的式子其实是

mi=1(2×i1)×26imi=1(2×i1)×26i

其中m=n+12m=n+12
这东西显然一个差比数列,裂项相减一下

Ans=mi=1(2×i1)×26iAns=mi=1(2×i1)×26i

26Ans=mi=1(2×i1)×26i+126Ans=mi=1(2×i1)×26i+1

25Ans=26+(2n1)×26n+12×mi=126i25Ans=26+(2n1)×26n+12×mi=126i

25Ans=26+(2n1)×26n+12×26n+1262525Ans=26+(2n1)×26n+12×26n+12625

直接快速幂即可

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x>=10)	print(x/10);
	putchar(x%10+'0');
}
const int p=1e9+7,inv=2.8e8+2,inv2=5.6e8+5;
int mlt(int a,int b){
	int res=1;
	for (;b;b>>=1,a=1ll*a*a%p)	if (b&1)	res=1ll*res*a%p;
	return res;
}
int main(){
	for (int T=read();T;T--){
		int n=(read()+1)>>1;
		int Ans=(1ll*(26+1ll*(2*n-1)*mlt(26,n+1)%p-2ll*(mlt(26,n+1)-26)%p*inv%p)*inv%p+p)%p;
		printf("%d\n",Ans);
	}
	return 0;
}

抓住czx

题目背景:
蒟蒻ltylty出了一道题,但是由于太弱了,所以希望喜欢鸽子的czxczx来帮他写一个stdstd。由于czxczx又放鸽子去了,所以没有写stdstd。蒟蒻ltylty觉得受到了学长的鄙视,所以决定去czxczx放鸽子的地方找他。

题意简述:
czxczx放鸽子的地方是一个公园,公园珂以看作是由nn个点mm条边组成的无向图(保证无自环),ltylty将从公园的入口(bb号节点)进去寻找czxczx,而czxczx会在aiai个单位时间时变化位置到第xx个节点去,在此之前ltylty已经知道了czxczx的具体位置和接下来他位置的变化方案,蒟蒻ltylty现在想知道他至少需要花多少时间找到czxczx

输入格式:

第一行四个整数nn,mm,bb,ee,bbee的意义如题面所示。

接下来mm行,每行三个整数x,y,zx,y,z,表示xxyy之间有一条长为zz的边。

m+1m+1行一个整数TT,表示czxczx位置变化的次数。

接下来TT行,每行两个整数aiaixx,表示czxczx将在第aiai个单位时间时移动到第xx个点上去。

输出格式:

一个整数表示最短所需时间。

样例输入:

6 9 1 6
1 2 1
1 3 3
1 4 4
2 3 2
3 6 6
4 5 6
2 5 9
3 5 7
5 6 2
3
10 3
8 5
9 2

样例输出:

9

样例解释:

在开始的时候就直接走到22号节点,然后等到czxczx过来。总花费时间99个单位时间。

数据范围:

对于30%的数据,n<=100n<=100,m<=1000m<=1000,T<=100T<=100

对于另外30%的数据,T=0T=0

对于100%的数据,n<=105n<=105,m<=5×105m<=5×105,T<=105T<=105

数据结果保证在intint范围内

题解:

关于SPFASPFA:它还活着(本来想卡的。。。)

30%:瞎jbjb弄吧,其实我也不知道这个部分分有啥意义。。。

另外30%:单源最短路板子。(其实是数据太大放不上。。。强行减小数据大小)

100%:首先求一遍单源最短路,如果我们出发去找czxczx,但是半路中czxczxTPTPMCMC玩家)走了,那么我们不如最开始就找之后的某个点。这样就可以找到一个点,在czxczx下次TPTP前抓住他即可。

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x>=10)	print(x/10);
	putchar(x%10+'0');
}
const int N=1e5,M=1e6;
int pre[(M<<1)+10],now[N+10],child[(M<<1)+10],val[(M<<1)+10];
int h[N+10],deep[N+10];
bool vis[N+10];
int n,m,S,tot;
struct S1{
	int x,T;
	void insert(int _x,int _T){x=_x,T=_T;}
	bool operator <(const S1 &a)const{return T<a.T;}
}A[N+10];
void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
void SPFA(int x){
	int head=0,tail=1;
	memset(deep,63,sizeof(deep));
	h[1]=x,vis[x]=1,deep[x]=0;
	while (head!=tail){
		if (++head>N)	head=1;
		int Now=h[head];
		for (int p=now[Now],son=child[p];p;p=pre[p],son=child[p]){
			if (deep[son]>deep[Now]+val[p]){
				deep[son]=deep[Now]+val[p];
				if (!vis[son]){
					if (++tail>N)	tail=1;
					vis[h[tail]=son]=1;
				}
			}
		}
		vis[Now]=0;
	}
}
int main(){
	n=read(),m=read(),S=read(),A[0].insert(read(),0);
	for (int i=1;i<=m;i++){
		int x=read(),y=read(),z=read();
		join(x,y,z),join(y,x,z);
	}
	SPFA(S);
	int T=read();
	for (int i=1;i<=T;i++){
		int x=read(),y=read();
		A[i].insert(y,x);
	}
	A[++T].insert(0,inf);
	sort(A,A+1+T);
	for (int i=0;i<=T;i++){
		if (deep[A[i].x]<A[i+1].T){
			printf("%d\n",max(deep[A[i].x],A[i].T));
			break;
		}
	}
	return 0;
}
posted @   Luvwgyx  阅读(990)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· 程序员常用高效实用工具推荐,办公效率提升利器!
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 【译】WinForms:分析一下(我用 Visual Basic 写的)
点击右上角即可分享
微信分享提示