最近做题遇到的坑·第二弹 cf976d,agc022_c,cf1000f,cf1039d,cf1042f,cf850c,cf727f,cf761f,cf501e,cf735e

本文介绍了博主在算法和数据结构学习过程中的体验,包括遇到的题目和解题心得。从CF(Codeforces)比赛题目中提炼出若干经典问题,如主席树的应用、贪心算法在树上的应用、博弈论问题以及前缀和计算等。通过实例展示了如何运用这些算法解决实际问题,并反思了自己的学习过程,强调了理解和实践的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cf976d

一道yzy两年前就秒了的题我今天还不会而且竟然看不懂yzy写的题解
构造题,构造方法不少,yzy的看上去最nb,不过我哪一种都不会,写了个random_shuffle竟然过了

agc022_c

没什么营养的 思维题,没有什么难度

cf1000f

5 × 1 0 5 5 \times 10^5 5×105级别,每次找一个区间只出现了一次的数

重新学习主席树
原来主席树每颗树里的叶子存的是pre[],前一次出现的位置
原来主席树modify(int &u,int v \quad u和v可以是 一样的
(数据结构不容易写出bug,比dp好调多了

cf1039d

树上最多有多少条点不重复的长度为k的路径

根本不知道可以贪心,。。
贺了之后发现不仅可以贪心,而且有个隐形的根号优化,因为长度大于 k \sqrt{k} k 的路径最多只有 k \sqrt{k} k 条,所以后面找到 a n s [ l ] = a n s [ r ] ans[l]=ans[r] ans[l]=ans[r]的时候中间的就可以都不用算了
(想必如果我知道贪心的话会发现这个性质

cf1042f

最少将一棵树上的点分成几组,使每组的点两两距离不超过K

也是树上贪心。不会,贺,发现我两年前的ac记录。。
转化成链不超过K,每个节点最长次长的儿子之和都 ≤ K \le K K的话不砍断,传最长的儿子上去;不然砍掉最长的儿子,继续判断

cf850c

博弈, N ≤ 100 N\le 100 N100 a [ i ] ≤ 1 0 9 a[i]\le 10^9 a[i]109,每次选一个 p k p^k pk(p是质数),把每个整除 p k p^k pk的数除 p k p^k pk
显然不同质因数独立。这题状态还只和所有a[i]中有无最高p^k有关。状压记搜搞搞就好了(是水题

cf727f

n ≤ 750 n\le 750 n750道题,每道题有愉悦值 − 1 0 9 ≤ a i ≤ 1 0 9 -10^9\le a_i\le 10^9 109ai109 ,初始有偷税值,从1到n验题,愉悦值爆负就凉凉,所以要删一些da♂rk题。 m ≤ 1 0 5 m\le 10^5 m105次询问,初始值为 b i b_i bi要删多少题

简单的dp题,先预处理删1~n个的最少初始愉悦值,二分即可。再二分回答每个答案

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
namespace IO {
	char buf[1<<22],*p1=buf,*p2=buf;
	#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin))==p1?EOF:*p1++)
	//#define gc getchar()
	inline LL rd() {
		LL t; scanf("%lld",&t); return t;
		LL x=0; int f=1; char c; while(isspace(c=gc));
		if(c=='-') f=-1,c=gc;
		do x=x*10+(c^48); while(isdigit(c=gc));
		return x*f;
	}
} using IO::rd;
int n,m,a[755];
LL s[755],mnb[755];
int dnum(LL b) {
	priority_queue<int> Q; LL sm=0; int re=0;
	for(int i=1;i<=n;++i) {
		Q.push(-a[i]);
		while(!Q.empty()&&s[i]+sm+b<0) {
			sm+=Q.top(); Q.pop(); ++re;
		}
	}
	return re;
}
int main() {
	n=rd(),m=rd();
	for(int i=1;i<=n;++i) a[i]=rd(),s[i]=s[i-1]+a[i];
	for(int i=0;i<=n;++i) {
		LL l=0,r=7.5e11;
		while(l<r) {
			LL mi=l+r>>1;
			if(dnum(mi)<=i) r=mi;
			else l=mi+1;
		}
		mnb[i]=-l;
	}
	while(m--) {
		printf("%d\n",lower_bound(mnb,mnb+n+1,-rd())-mnb);
	}
}

cf761f

求一波前缀和

我菜死了…一个大暴力前缀和打了3h,代码还比别人长这么多

#include<bits/stdc++.h>
#define FOR(it,s,t) for(int it=s;it<=t;++it)
#define REP(it,t,s) for(int it=t;it>=s;--it)
using namespace std;
typedef long long LL;
const int N=1005,Q=3e5+5;
int n,m,K,a[Q],b[Q],c[Q],d[Q];
char e[Q],mp[N][N];
LL ans[Q],g[26][N][N],h[26][N][N],f[N][N];
void dodododo(LL A[][N],int i,int v) {
	A[c[i]][d[i]]+=v;
	A[c[i]][b[i]-1]-=v;
	A[a[i]-1][d[i]]-=v;
	A[a[i]-1][b[i]-1]+=v;
}
void addadd(LL A[][N]) {
	REP(i,n,1) REP(j,m,1) A[i-1][j]+=A[i][j];
	REP(i,n,1) REP(j,m,1) A[i][j-1]+=A[i][j];
}
void sumsum(LL A[][N]) {
	FOR(i,1,n) FOR(j,1,m) A[i+1][j]+=A[i][j];
	FOR(i,1,n) FOR(j,1,m) A[i][j+1]+=A[i][j];
}
LL aaaa(LL A[][N],int i) {
	return A[c[i]][d[i]]
		-A[c[i]][b[i]-1]
		-A[a[i]-1][d[i]]
		+A[a[i]-1][b[i]-1];
}
int main() {
	scanf("%d%d%d",&n,&m,&K);
	for(int i=1;i<=n;++i) scanf("%s",mp[i]+1);
	for(int i=1;i<=K;++i) {
		scanf("%d%d%d%d",a+i,b+i,c+i,d+i);
		while(isspace(e[i]=getchar()));
		g[0][n][m]++;
		dodododo(g[0],i,-1);
		dodododo(h[e[i]-'a'],i,1);
	}
	addadd(g[0]);
	REP(o,25,0) REP(i,n,1) REP(j,m,1) g[o][i][j]=g[0][i][j]*abs(mp[i][j]-'a'-o);
	FOR(o,0,25) {
		memset(f,0,sizeof f);
		FOR(k,1,K) dodododo(f,k,abs(e[k]-'a'-o));
		addadd(f);
		REP(i,n,1) REP(j,m,1) g[o][i][j]+=f[i][j];
		sumsum(g[o]);
	}
	
	memset(f,0,sizeof f);
	FOR(o,0,25) {
		addadd(h[o]);
		REP(i,n,1) REP(j,m,1) f[i][j]+=h[o][i][j]*abs(mp[i][j]-'a'-o);
	}
	sumsum(f);
	
	LL ret=1e18;
	FOR(k,1,K) {
		ans[k]=aaaa(g[e[k]-'a'],k)+f[n][m]-aaaa(f,k);
		ret=min(ret,ans[k]);
	}
	cout<<ret;
}
	

cf501e

O ( n ) O(n)\quad O(n)扫一扫
窝太菜了- - 一个O(n)暴力又打了3h,分类讨论分得比标算垃圾得不知道哪里去了,算是复习了一下哈希吧

#include<bits/stdc++.h>
#define FOR(i,s,t) for(int i=s;i<=t;++i)
#define REP(i,t,s) for(int i=t;i>=s;--i)
using namespace std;
typedef long long LL;
const int N=1e5+5,HA=19260817;
int n;
map<int,LL> aka;
set<int> vals;
LL aa[N],xx[N],cc[N],oo[N],hh[N],ww[N];
LL ran() {
	static LL se=1;
	return se*=1000003;
}
int eq(int s,int t,int l) {
	return (oo[s]-oo[s+l]*hh[l])*hh[n+1-t]
		== (cc[t]-cc[t-l]*hh[l])*hh[s];
}
int wq(int s,int t,int l) {
	return (ww[s+l-1]-ww[s-1])==(ww[t]-ww[t-l]);
}
LL solve() {
	int o=0,i=0;
	LL re=0;
	while(o<n && eq(1,n,o+1)) ++o;
	
	if(o==n) cout<<1LL*n*(n+1)/2,exit(0);
	
	while(i*2<n && eq((n+1)/2-i,n/2+1+i,i+1)) ++i;
	
	if(wq(1+o,n-o,(n+1)/2-i-o)) re+=2LL*(1+o)*i;
	
cerr << "i= " << i << "    " << "o= " << o << endl;
cerr << "re= " << re << endl;
	if(vals.find(xx[n-o]^xx[o])!=vals.end()
		|| vals.find(xx[o]^xx[n-o])!=vals.end()) {
		re+=1LL*o*o-1;
		{
			map<LL,int> cn;
			FOR(i,o+1,n-o) ++cn[aa[i]];
			int r=n-o;
			while(cn[aa[r]]-2>=0) cn[aa[r--]]-=2;
			re+=(n-o-r+1)*(1LL+o);
	cerr << "r= " << r << endl;
		}
		{
			map<LL,int> cn;
			FOR(i,o+1,n-o) ++cn[aa[i]];
			int l=o+1;
			while(cn[aa[l]]-2>=0) cn[aa[l++]]-=2;
			re+=(l-o)*(1LL+o);
	cerr << "l= " << l << endl;
		}
	}
	
	return re;
}
		
	
int main() {
	ios::sync_with_stdio(0);
	vals.insert(0);
	hh[0]=1; FOR(i,1,N-1) hh[i]=hh[i-1]*HA;
	cin>>n;
	FOR(i,1,n) {
		int x; cin>>x;
		if(!aka.count(x)) vals.insert(aka[x]=ran());
		aa[i]=aka[x];
	}
	FOR(i,1,n) xx[i]=xx[i-1]^aa[i];
	FOR(i,1,n) cc[i]=cc[i-1]*HA+aa[i];
	REP(i,n,1) oo[i]=oo[i+1]*HA+aa[i];
	FOR(i,1,n) ww[i]=ww[i-1]+aa[i];
	cout<<solve();
}

cf735e

暴力不会写三连
普通的树上dp,我硬是把i=0 的值搞的和i=1 一样和后面相关,于是一塌糊涂,调不出来
每次都发现标算原来只要这么简单就行了

//又贺一题
#include<bits/stdc++.h>
#define FOR(i,s,t) for(int i=s;i<=t;++i)
#define REP(i,t,s) for(int i=t;i>=s;--i)
using namespace std;
typedef long long LL;
const int MO=1e9+7;
int n,K;
LL dp[105][44],tt[44];
vector<int> e[105];
void add(LL &x,LL y) { x=(x+y)%MO; }
void mul(LL &x,LL y) { x=x*y%MO; }
void dfs(int u,int f) {
	dp[u][K+1]=1;
	dp[u][0]=1;
	for(auto v:e[u]) if(v!=f) {
		dfs(v,u);
		FOR(i,0,2*K)
		FOR(j,0,2*K)
			add(tt[i+j<=2*K ? min(i,j+1) : max(i,j+1)],dp[u][i]*dp[v][j]);
		memcpy(dp[u],tt,sizeof tt);
		memset(tt,0,sizeof tt);
	}
}
int main() {
	cin>>n>>K;
	for(int i=1,x,y;i<n;++i) {
		cin>>x>>y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dfs(1,0);
	LL ans=0; FOR(i,0,K) add(ans,dp[1][i]); cout<<ans<<endl;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值