Nov 20

今天依然是爆炸的一天,第一题因为使用了下标访问了 map 而导致了 tle, T1 直接 100 -> 60,觉得写一些赛后总结会好很多,最近也不想写什么题了,于是便总结总结吧。

比赛经验上的

似乎真的有 OI 教练模拟器的虎头蛇尾的 tag 了,只有比赛开始的一个小时能够正常的思考。

感觉对于我来说集中注意力一个小时以上很困难。

之后尝试给自己留十几分钟休息时间试一下。

到现在我才知道了运行代码的时候可以通过 time ./文件名 来知道我的文件运行时间,感谢 langmouren 的告知,我之前一直使用 clock(),这个样子似乎确实方便一些。

不知道有没有什么静心的方法,今天晚上学习一下冥想。

最近的题似乎难度普遍的低了一些,似乎想练习我的的做题习惯?今天似乎 T2 最难。

没了。

题目上的

T1 S2OJ 33

水题。

看起来不是 dp 就是贪心。

发现斐波那契数列的增长极度快速,在第四十多项就会达到 2e9 级别,是可以枚举判断的。

我们发现了一个性质,就是一次划分的贡献为一,这个性质通常可以导向贪心。

我们考虑一下从左向右扫,能放到当前段的就放,任何冲突都会导致划分到不同两个段中,贡献不变,贪心正确。

而我使用了 map 维护当前段中的值出现情况,但是使用 [] 访问,所以 tle 了,改成 .count() 查询就好了。

代码↓

点击查看代码
#include <bits/stdc++.h>
#define getchar getchar_unlocked
#define int long long
using namespace std;
const int MN=1e5+115;
int f[MN], a[MN], n;
inline 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 Read(){
	n=read();
	for(int i=1; i<=n; ++i) a[i]=read();
	return;
}
unordered_map <int,int> exist;
void Solve(){
	Read();
	int ans=0;
	for(int i=1; i<=n; ++i){
		if(exist.empty()){
			ans++; exist[a[i]]=true;
			continue;
		}
		for(int j=1; j<=45; ++j){
			if(exist.count(f[j]-a[i])){
				ans++;
				exist.clear();
				break;
			}
		}
		exist[a[i]]=true;
	}
	cout<<ans<<'\n';
	return;
}
signed main(){
	//clock_t  Begin, End;
    //double duration; Begin=clock();
	//freopen("f.in","r",stdin);
	//freopen("f.out","w",stdout);
	f[0]=0; f[1]=1;
	for(int i=2; i<=50; ++i) f[i]=f[i-1]+f[i-2];
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	Solve();
	//End=clock();
	//duration=double(End-Begin)/CLOCKS_PER_SEC;
    //cout<<"tick="<<double(End-Begin)<<endl;
    //cout<<"运行时间: "<<duration<<"s"<<endl;	
	return 0;
}
/*
回家想玩游戏打开卡兹天梯
带上我的日快闪击 所向无敌
来到对局第一把是炸槽的霓虹兵
习志野 35t 中消防局都打一
穷兵加上亡命之计
我疲软无力 阔土大飞机
再出山本八乘七
面对如此这般强敌
我只能右上角逃逸 
*/

T2 S2OJ 34

神秘题。

有两个对于中位数的限制,不太好搞的样子。

问题需要知道中位数的一些小性质。

如果区间中位数 \(\le\) x。

我们可以得到了 (区间中\(\le\) x 的元素个数) \(\ge\) (区间中大于 x 的元素个数)

然而介个有神马用呢?

我们考虑一个区间的中位数 \(\le\) val

使用一次前缀和求出来每一个位置。

对于 \([j+1,i]\) 区间中。

\(\le\) val 的元素个数 cnt=sum[i]-sum[j]

\(>\) val 的元素个数是 (i-j)-cnt

我们按照中位数性质可以化简出来

2 * sum[i] - i \(\ge\) 2 * sum[j] - j

我们每一次存一下就好了,我们就扫一下,树状数组维护,没有了,好题一个。

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define getchar getchar_unlocked
using namespace std;
const int MN=1e6+116;
inline 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;
}
struct BIT{
	int tr[MN], n=MN;
	void init(){
		memset(tr,0,sizeof(tr));
	}
	int lowbit(int x){
		return x&(-x);
	}
	void update(int pos, int val){
		pos+=2e5+215;
		for(int i=pos; i<=n; i+=lowbit(i)) tr[i]+=val;
		return;
	}
	int qval(int pos){
		int res=0; pos+=2e5+215;
		for(int i=pos; i; i-=lowbit(i)) res+=tr[i];
		return res;
	}
}tr;
int sum[MN], n, a[MN];
int Get(int pos, int l, int r){
	tr.init(); memset(sum,0,sizeof(sum));
	for(int i=1; i<=n; ++i){
		sum[i]=(sum[i-1]+(a[i]<=pos));
	}
	int res=0; ++r;
	for(int i=l; i<=n; ++i){
		tr.update(2*sum[i-l]-(i-l),1);
		if(i>=r) tr.update(2*sum[i-r]-(i-r),-1);
		res+=tr.qval(2*sum[i]-i);
	}
	return res;
}
void Read(){
	n=read(); for(int i=1; i<=n; ++i) a[i]=read();
}
void Solve(){
	Read(); int q; q=read();
	while(q--){
		int l1, r1, l2, r2;
		l1=read(); r1=read();
		l2=read(); r2=read();
		cout<<Get(r1,l2,r2)-Get(l1-1,l2,r2)<<'\n';
	}
	return;
}
signed main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	Solve();
	return 0;
}

T3 S2OJ 35

人类智慧题。

发现两个点可以互相到达当且仅当两个点所属的矩形集合相同。

考虑哈希,需要可以删除,考虑异或哈希,给每一个矩形一个随机值。

使用二维树状数组维护,就没有了,很简单,但我场上并没有看这道题。

代码↓

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define getchar getchar_unlocked
using namespace std;
const int MN=3555;
inline 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;
}
struct BIT{
	int n, m, tr[MN][MN];
	int lowbit(int x){
		return x&(-x);
	}
	void update(int x, int y, int val){
		for(int i=x; i<=n; i+=lowbit(i)){
			for(int j=y; j<=m; j+=lowbit(j)){
				tr[i][j]^=val;
			}
		}
	}
	int qval(int x, int y){
		int res=0;
		for(int i=x; i; i-=lowbit(i)){
			for(int j=y; j; j-=lowbit(j)){
				res^=tr[i][j];
			}
		}
		return res;
	}
}tr;
int n, m, q;
struct Node{
	int x1, x2, y1, y2;
	bool operator <(const Node &o)const{
		if(x1!=o.x1) return x1<o.x1;
		if(x2!=o.x2) return x2<o.x2;
		if(y1!=o.y1) return y1<o.y1;
		return y2<o.y2;
	}
};
map <Node,int> hashed;
void Solve(){
	n=read(); m=read(); q=read();
	tr.n=n; tr.m=m;
	for(int i=1; i<=q; ++i){
		int op, x1, y1, x2, y2;
		op=read(); x1=read(); y1=read();
		x2=read(); y2=read();
		if(op==1){
			int key=rand();
			tr.update(x1,y1,key);
			tr.update(x1,y2+1,key);
			tr.update(x2+1,y1,key);
			tr.update(x2+1,y2+1,key);
			hashed[{x1,x2,y1,y2}]=key;
		}else if(op==2){
			int key=hashed[{x1,x2,y1,y2}];
			tr.update(x1,y1,key);
			tr.update(x1,y2+1,key);
			tr.update(x2+1,y1,key);
			tr.update(x2+1,y2+1,key);
		}else{
			if(tr.qval(x1,y1)==tr.qval(x2,y2)) cout<<"Yes\n";
			else cout<<"No\n";
		}
	}
	return;
}
signed main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	Solve();
	return 0;
}

T4 S2OJ 112

哈基米曼波题。

发现数据范围很小,但并没有小到可以直接暴力搜索。

不过如果要爆搜,范围需要小一半,我们考虑 meet in middle。

跑出来所有的集合,sort 一下,二分答案进行合并。

一定不要忘记在每一个几个内部进行答案统计。

代码↓

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define getchar getchar_unlocked
using namespace std;
const int MN=44;
vector <int> a, b;
int n, m, s[MN], ans=0;
inline 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 Read(){
	n=read(); m=read();
	for(int i=1; i<=n; ++i) s[i]=read();
	return;
}
void dfsl(int l, int r, int sum){
	if(l>r){
		a.emplace_back(sum);
		ans=max(ans,sum%m);
		return;
	}
	dfsl(l+1,r,sum);
	dfsl(l+1,r,(sum+s[l])%m);
	return;
}
void dfsr(int l, int r, int sum){
	if(l>r){
		b.emplace_back(sum);
		ans=max(ans,sum%m);
		return;
	}
	dfsr(l+1,r,sum);
	dfsr(l+1,r,(sum+s[l])%m);
	return;
}
void Solve(){
	Read(); int mid=n/2;
	dfsl(1,mid,0); dfsr(mid+1,n,0);
	sort(a.begin(),a.end());
	sort(b.begin(),b.end());
	for(auto v:a){
		int k=*(upper_bound(b.begin(),b.end(),m-v-1)-1);
		ans=max(ans,(v+k)%m);
	}
	cout<<ans<<'\n';
	return;
}
signed main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	Solve(); return 0;
}

希望明天的比赛我可以打好。

posted @ 2025-11-20 19:11  BaiBaiShaFeng  阅读(14)  评论(0)    收藏  举报
Sakana Widget右下角定位