2024-03-15

2024-03-15

美好的一天

昨天剩下的题
一个字符串重新标号之后可以形成回文串 当且仅当 每个字母在这个串中出现的次数要么全是偶数 要么只有一个奇数
我们只关心出现次数的奇偶性,可以用异或来记录
用一个长度为 26 的 01 串 st 来记录,第 i 位表示 ('a'+i) 这个字母出现次数的奇偶性
把字符串扫描一遍 在每个位置 ist 异或上 (1<<(s[i]-'a'))
但是要快速提取出子串的信息
st 存成前缀和的形式就行

问题转化为
在每个区间 \([l-1,r]\) 中,有多少对 \(i<j\) 使得 st[i]^st[j]==0st[i]^st[j]==(1<<k)
根据异或的性质 统计 st[i]==st[j]st[i]==st[j]^(1<<k) 的个数即可
可以用莫队实现

  1. 添加一个位置 x
    • 统计之前已有的 st[x] 的数量
    • 统计与 st[x] 只有一位不同的数量
    • st[x] 的数量 +1
  2. 删除一个位置
    • st[x] 的数量 -1
    • 除去删除后 st[x] 的数量
    • 除去与 st[x] 只有一位不同的数量

顺序很重要

finished

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;

const int N=60060;

int n,m;
char s[N];
int st[N];
int cnt[(1<<26)+5];
int res;
int len;

#define blk(x) ((x-1)/len+1)

struct Query {
	int id;
	int l,r;
	friend bool operator < (Query A,Query B) {
		if(blk(A.l)==blk(B.l)) return A.r<B.r;
		return blk(A.l)<blk(B.l);
	}
}Q[N];

int ans[N];

void add(int x) {
	res+=cnt[st[x]];
	for(int i=0;i<26;i++) res+=cnt[st[x]^(1<<i)];
	cnt[st[x]]++;
}

void del(int x) {
	cnt[st[x]]--;
	res-=cnt[st[x]];
	for(int i=0;i<26;i++) res-=cnt[st[x]^(1<<i)];
}

int main() {
	scanf("%d%d%s",&n,&m,s+1);
	len=n/sqrt(m);
	for(int i=1;i<=n;i++) st[i]=st[i-1]^(1<<(s[i]-'a'));
	for(int i=1;i<=m;i++) scanf("%d%d",&Q[i].l,&Q[i].r),Q[i].id=i;
	sort(Q+1,Q+m+1);
	int p=0,q=1;
	for(int c=1;c<=m;c++) {
		int x=Q[c].l-1,y=Q[c].r;
		while(p<y) add(++p);
		while(q>x) add(--q);
		while(q<x) del(q++);
		while(p>y) del(p--);
		ans[Q[c].id]=res;
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
	
	return 0;
}

Pudding Monsters (CodeForces 526 F)

# 简述题意 #
有一个 \(n\times n\) 的棋盘,每行每列都恰好有一个棋子,问有多少个 \(k\times k \ (k\in [1,n])\) 的子棋盘满足恰好有 \(k\) 个棋子

将二维问题转化为一位
一个长为 \(n\) 的序列,每一位存的是这一纵坐标上的棋子的横坐标
那么原来的问题就变成了

有多少个子序列 \([l, r]\) 使得 \(max-min=r-l\)

移项得 \(max-min+l-r=0\)

等于零不好维护,注意到 \(max-min+l-r\ge 0\) 那么我们要求的就是最小值的个数

枚举所有前缀,那么所有前缀的后缀就是所有子序列

用线段树来维护当前所有后缀的 \(max-min+l-r\) 值的最小值和最小值的个数

分四个部分维护

  1. \(l\) : 每个后缀的左端点一直是不变的 因此一开始 build 线段树的时候就把 val 设置为 lft 就行
  2. \(r\) : 右端点每向后移动一次 所有后缀的 r 就加一,区间 -1 即可
  3. \(max\) : 用单调栈维护,每次要弹出的时候说明左端点为从 stk[top-1]+1stk[top] 的这些后缀的 max 需要修改,减去原来的值,加上新加入的纸即可
  4. \(min\) : 同 max,但是 min 前面是负号,所以加上原来的值,减去新加入的值

在每个右端点处都统计答案
就完了

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long ll;

const int N=3e5+10;

int n;

struct Segtree {
	#define ls (u<<1)
	#define rs (u<<1|1)
	struct Node {
		int l,r;
		ll val,num;
		ll tag;
	}tr[N*4];
	void build(int u,int lft,int rgh) {
		tr[u].l=lft,tr[u].r=rgh;
		tr[u].num=1,tr[u].val=lft;
		if(lft==rgh) return;
		int mid=lft+rgh>>1;
		build(ls,lft,mid),build(rs,mid+1,rgh);
	}
	void pushup(int u) {
		tr[u].val=min(tr[ls].val,tr[rs].val);
		tr[u].num=0;
		if(tr[ls].val==tr[u].val) tr[u].num+=tr[ls].num;
		if(tr[rs].val==tr[u].val) tr[u].num+=tr[rs].num;
	}
	void pushdown(int u) {
		if(!tr[u].tag) return;
		tr[ls].val+=tr[u].tag,tr[rs].val+=tr[u].tag;
		tr[ls].tag+=tr[u].tag,tr[rs].tag+=tr[u].tag;
		tr[u].tag=0;
	}
	void update(int u,int ul,int ur,ll k) {
		if(tr[u].l>=ul&&tr[u].r<=ur) {
			tr[u].val+=k,tr[u].tag+=k;
			return;
		}
		pushdown(u);
		int mid=tr[u].l+tr[u].r>>1;
		if(ul<=mid) update(ls,ul,ur,k);
		if(ur>mid) update(rs,ul,ur,k);
		pushup(u);
	}
}T;

struct Pudding {
	int x,y;
	friend bool operator < (Pudding A,Pudding B) {
		return A.x<B.x;
	}
}a[N];

int stkmx[N],stkmn[N];
int tpmx,tpmn;

ll ans;

int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1);
	T.build(1,1,n);
	for(int i=1;i<=n;i++) {
		T.update(1,1,n,-1);
		while(tpmx&&a[stkmx[tpmx]].y<a[i].y) T.update(1,stkmx[tpmx-1]+1,stkmx[tpmx],a[i].y-a[stkmx[tpmx]].y),tpmx--;
		stkmx[++tpmx]=i;
		while(tpmn&&a[stkmn[tpmn]].y>a[i].y) T.update(1,stkmn[tpmn-1]+1,stkmn[tpmn],a[stkmn[tpmn]].y-a[i].y),tpmn--;
		stkmn[++tpmn]=i;
		ans+=T.tr[1].num;
	}
	printf("%lld\n",ans);
	
	return 0;
}

晚上和初三的一块听课,群论,掉线了……

然后看了一晚上的数学……

复习了一下莫比乌斯变换/反演
在看 # 约数个数和 # 这道题的时候
看到了这个公式

\[d(x \cdot y)=\sum_{i\mid x}\sum_{j\mid y}[(i,j)=1] \]

\(d(x)\) 表示 \(x\) 的约数个数
还是有必要记住的

数学真的很弱诶,有必要弄一个数学集锦了

然后研究了老师发的数学的课件

posted @ 2024-03-15 18:51  OrangeStar*  阅读(8)  评论(0编辑  收藏  举报