ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

9.15-CSP-S开小灶4

2022-09-16 11:03:40  阅读:189  来源: 互联网

标签:pre int siz 9.15 long maxn 开小灶 CSP define


T1 山洞

比较简单但是我脑子抽了绕了半天弯。
朴素dp是很好写的
$ dp[i][j]= dp[i-1][j-i]+dp[i-1][j+i] ,(j-i \neq j+i)$

考虑优化,我们可以先暴力推出前n步(当然最大可以推到10000步好像也没问题),然后我们一次走n步,这样会一共走m/n次,然后剩下m%n次仍然暴力推就行。中间一次走n步的实际上就是循环卷积,可以倍增卷,于是就切了。

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=1e3+10,Mod=1e9+7,inv2=500000004;
int pw(int x,int p){int res=1,base=x;while(p){if(p&1)res=1LL*res*base%Mod;base=1LL*base*base%Mod;p>>=1;}return res;}
int Inv(int x){return pw(x,Mod-2);}
int dp[maxn][maxn];
int n,m;
int bs[maxn];
int Ans[maxn];

void Work1(){
	dp[0][0]=1;
	for(int i=1;i<=m;++i){
		for(int j=0;j<n;++j){
			int pre=(j+n-(i%n))%n,nxt=(j+i)%n;
			dp[i][nxt]=(dp[i][nxt]+dp[i-1][j])%Mod;
			if(pre!=nxt)dp[i][pre]=(dp[i][pre]+dp[i-1][j])%Mod;
		}
	}
	cout<<dp[m][0];
}

int tr[maxn],ta[maxn],tb[maxn];

void Mul(int *res,int *a,int *b){
	for(int i=0;i<n;++i)ta[i]=a[i],tb[i]=b[i];
	for(int i=0;i<n;++i)res[i]=0;
	for(int i=0;i<n;++i)for(int j=0;j<n;++j)
		res[(i+j)%n]=(res[(i+j)%n]+1LL*ta[i]*tb[j])%Mod;
}

void solve(){
	cin>>n>>m; if(m<=n)return Work1();
	dp[0][0]=1;
	for(int i=1;i<=n;++i){
		for(int j=0;j<n;++j){
			int pre=(j+n-(i%n))%n,nxt=(j+i)%n;
			dp[i][nxt]=(dp[i][nxt]+dp[i-1][j])%Mod;
			if(pre!=nxt)dp[i][pre]=(dp[i][pre]+dp[i-1][j])%Mod;
		}
	}
	for(int j=0;j<n;++j)bs[j]=dp[n][j];
	m-=n;int k=m/n;
	for(int j=0;j<n;++j)Ans[j]=bs[j];
	while(k){ if(k&1)Mul(Ans,Ans,bs); Mul(bs,bs,bs); k>>=1; }
	m%=n; memset(dp,0,sizeof(dp));
	for(int j=0;j<n;++j)dp[0][j]=Ans[j];
	for(int i=1;i<=m;++i){
		for(int j=0;j<n;++j){
			int pre=(j+n-(i%n))%n,nxt=(j+i)%n;
			dp[i][nxt]=(dp[i][nxt]+dp[i-1][j])%Mod;
			if(pre!=nxt)dp[i][pre]=(dp[i][pre]+dp[i-1][j])%Mod;
		}
	}
	cout<<dp[m][0];
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }

T2 beauty

挺水的,考虑每条边的贡献,它两边的关键点的量分别\(x\)和\(2 * k - x\),显然能把两边连起来我一定不会在其中一边自己连,于是就是一条边的贡献就是两边点的数量取min,对于方案的构造可以考虑从重心一点一点配。

赛时写了一个需要特判链的做法,拿了非特殊性质的分,本质上与上面的做法相同,就是考虑在一棵子树上的根处给路径配对,对于这个根来讲,显然我能在它的儿子子树间配对就一定不会在儿子子树内配对,像摩尔投票一样,把所有儿子子树的关键点的数量统计出来,只要没有出现绝对众数,那么只在儿子子树间配对的构造就是可行的,否则我们找出关键点最多的儿子子树,子树内其他关键点都和最大子树的关键点配对,然后剩下一部分递归进最大子树内处理,同时记录一下子树内有多少个节点被拿到外边和其他子树的点匹配了,每次递归进一棵子树时,先把对于出去的那些点,子树根和其父亲的连边的贡献算上。有70分,但是在链上的话,显然就是首尾配对,但是这个做法会相邻的配对,于是就锅了。

upd:赛时做法不用特判链,我想麻烦了。显然链上的做法就是每次都拿首尾配对,于是在单儿子下传pre的那部分里,考虑一下儿子子树内的点还够不够拿出去配对,够就给pre加一,否则就把自己拿出去给上边配对,也就是给pre-1,就可以过掉链的情况。

赛时做法


#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=1e5+10,maxm=2e5+10;

ll ans;

struct Graph{
	struct eg{int from,to,next;}e[maxm];
	int len,head[maxn];int fa[maxn],val[maxn],siz[maxn];
	int pre[maxn],dis[maxn];
	vector<int>son[maxn];
	void lqx(int from,int to)
	{ e[++len].from=from,e[len].to=to,e[len].next=head[from],head[from]=len; }
	void Dfs(int u){
		siz[u]=val[u];
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;if(v==fa[u])continue;
			fa[v]=u;son[u].push_back(v);Dfs(v);
			siz[u]+=siz[v];
			dis[u]+=dis[v]+siz[v];
		}
	}
	void Dp(int u){
		int sum=0,mx=0;ans+=pre[u];
		if(son[u].empty())return;
		if(son[u].size()==1){
			if(val[u]){
				if(pre[u]+1>siz[son[u][0]])pre[son[u][0]]+=pre[u]-1;
				else pre[son[u][0]]+=pre[u]+1;
			}else pre[son[u][0]]+=pre[u];
			return Dp(son[u][0]);
		}
		for(auto v : son[u])sum+=siz[v],mx=max(siz[v],mx);
		if(mx-pre[u]>siz[u]-mx){
			int tx=0,tv=0;
			for(auto v : son[u])if(siz[v]!=mx)ans+=dis[v]+siz[v],tx+=siz[v];
			else tv=v;
			pre[tv]+=pre[u]+tx+val[u];
			Dp(tv);
			
		}else{ans+=dis[u];return;}
	}
}G;

int spe[maxn];
int n,k,tpy;

void solve(){
	cin>>n>>k>>tpy;int x,y;
	Rep(i,1,2*k)cin>>spe[i],G.val[spe[i]]=1;
	Rep(i,2,n)cin>>x>>y,G.lqx(x,y),G.lqx(y,x);
	G.Dfs(1);G.Dp(1);
	cout<<ans<<"\n";
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }


题解做法


#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=1e5+10,maxm=2e5+10;

ll ans;
int n,k,tpy;

struct Graph{
	struct eg{int from,to,next;}e[maxm];
	int len,head[maxn];int fa[maxn],val[maxn],siz[maxn];
	int pre[maxn],dis[maxn];
	vector<int>son[maxn];
	void lqx(int from,int to)
	{ e[++len].from=from,e[len].to=to,e[len].next=head[from],head[from]=len; }
	void Dfs(int u){
		siz[u]=val[u];
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;if(v==fa[u])continue;
			fa[v]=u;son[u].push_back(v);Dfs(v);
			siz[u]+=siz[v];
			dis[u]+=dis[v]+siz[v];
		}
	}
	void Dp(int u){
		if(fa[u]){
			ans+=min(siz[u],2*k-siz[u]);
		}
		for(auto v : son[u])Dp(v);
	}
}G;

int spe[maxn];

void solve(){
	cin>>n>>k>>tpy;int x,y;
	Rep(i,1,2*k)cin>>spe[i],G.val[spe[i]]=1;
	Rep(i,2,n)cin>>x>>y,G.lqx(x,y),G.lqx(y,x);
	G.Dfs(1);G.Dp(1);
	cout<<ans<<"\n";
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }


标签:pre,int,siz,9.15,long,maxn,开小灶,CSP,define
来源: https://www.cnblogs.com/Delov/p/16698060.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有