爱与时间反应鲜红色慢慢退却 一次次重复直到忘记了誓言 放弃这无果努力不再浪费时间 让心忘记所有感觉 直到永远

test48

字符串

特判 \(k=1\),然后 \(abab...\) 最后以此填写 \(cde...\)

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)

using namespace std;

int n, k;

signed main() {
	freopen("str.in","r",stdin);
	freopen("str.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> k;
	if(k==1) {
		if(n==1) cout << 'a' << '\n';
		else cout << -1 << '\n';
		return 0;
	}
	if(n<k) { cout << -1 << '\n'; return 0; }
	up(i,1,n-k+2) cout << ((i&1)?'a':'b');
	up(i,3,k) cout << char('a'+i-1);
	return 0;
}

城堡

发现是 \([1,k]\) 形成一棵 \(1\) 在环上的基环树,所以 \((k,n]\) 不能往 \([1,k]\) 连边。因为 \(k\leq 8\) 前面的部分可以爆搜,后面则显然是 \((n-k)^{n-k}\) 了。

但是 g1ove 大神发现答案是 \(k^{k-1}(n-k)^{n-k}\),前面可以看做 \(k^{k-2}\times k\),prufer 一个无根树然后从 \(1\) 开一个环形,因为是有向图不会重。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)

using namespace std;

const int N=15, P=1e9+7;

int ksm(int a,int b=P-2) {
	a%=P;
	int res=1;
	for( ; b; b>>=1) {
		if(b&1) res=res*a%P;
		a=a*a%P;
	}
	return res;
}

int n, m, ans, sav[]={0,1,2,9,64,625,7776,117649,2097152};

signed main() {
	freopen("castle.in","r",stdin);
	freopen("castle.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	ans=sav[m]*ksm(n-m,n-m)%P;
	cout << (ans%P+P)%P << '\n';
	return 0;
}

电梯

\(f[i][j]\) 表示考虑到 \(i\) 步,在 \(j\) 的方案数,发现转移是向 \(f[i+1][]\) 的区间,那么差分优化即可,然后因为题目不能原地踏步最后减一下(

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)

using namespace std;

const int N=5005, P=1e9+7;

int n, s, t, m, ans, f[N][N];

inline void add(int &a,int b) { a=(a+b)%P; }

signed main() {
	freopen("lift.in","r",stdin);
	freopen("lift.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> s >> t >> m;
	f[0][s]=1;
	up(i,1,m) {
		up(j,1,n) if(f[i-1][j]&&j!=t) {
			if(j<t) {
				int l=max(1ll,2*j-t+1);
				add(f[i][l],+f[i-1][j]);
				add(f[i][t],-f[i-1][j]);
			}
			else {
				int r=min(n,2*j-t-1);
				add(f[i][t+1],+f[i-1][j]);
				add(f[i][r+1],-f[i-1][j]);
			}
		}
		up(j,1,n) add(f[i][j],f[i][j-1]);
		up(j,1,n) add(f[i][j],-f[i-1][j]);
	}
	up(i,1,n) add(ans,f[m][i]);
	cout << (ans%P+P)%P << '\n';
	return 0;
}

分组

题目套了个虚树的壳子,提出虚树之后变成做普通线性 dp,然后会多一些无贡献的虚点,但是这个题目其实本质上你可以直接删掉假的点连边所以虚点也不重要其实。

直接 \(f[u][i]\) 表示子树 \(u\)\(i\) 种颜色什么的转移根本就是 \(m^3\) 好嘛,不能这么做。换个角度思考,每个点不能根祖先同组,那么一条祖先链条上的限制是不断边紧的(其实方向看你先填哪一端),祖先选的颜色肯定两两不同,就是有 \(dep_u-1\) 个颜色不能填这种感觉,那你保证先选祖先的组别就好了,那么按照 dfn 来 dp 即可。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back 

using namespace std;

const int N=100005, M=21, P=1e9+7;

int n, q, T, k, fa[N][M], dep[N], dfn[N], stp;
int u[N<<2], tag[N], f[N][305], top, p[N];
vector<int> to[N], sav[N];

void dfs(int x,int fad) {
	dfn[x]=++stp, dep[x]=dep[fad]+1, fa[x][0]=fad;
	up(i,1,T) fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int y:to[x]) if(y!=fad) dfs(y,x);
}

int lca(int x,int y) {
	if(dep[x]<dep[y]) swap(x,y);
	dn(i,T,0) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
	if(x==y) return x;
	dn(i,T,0) if(fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i];
	return fa[x][0];
}

void dp(int x,int fad,int len) {
	if(!tag[x]) {
		for(int y:sav[x]) if(y!=fad) dp(y,x,len);
	}
	else {
		++top;
		if(len>k) {
			up(i,0,k) f[top][i]=0;
			return;
		}
		up(i,0,len-1) f[top][i]=0;
		up(i,len,k) f[top][i]=(f[top-1][i-1]+f[top-1][i]*(i-len)%P)%P;
		for(int y:sav[x]) if(y!=fad) dp(y,x,len+1);
	}
}

signed main() {
    freopen("group.in","r",stdin);
    freopen("group.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> q, T=__lg(n);
	up(i,2,n) {
		int u, v;
		cin >> u >> v;
		to[u].pb(v);
		to[v].pb(u);
	}
	dfs(1,0);
	while(q--) {
		int m, rt, ans=0, len;
		cin >> m >> k >> rt, p[0]=u[len=1]=rt;
		up(i,1,m) cin >> p[i], tag[p[i]]=1, u[++len]=p[i]; 
		sort(p,p+1+m,[](int i,int j){return dfn[i]<dfn[j];});
		up(i,1,m) u[++len]=lca(p[i],p[i-1]);
		sort(u+1,u+1+len), len=unique(u+1,u+1+len)-u-1;
		sort(u+1,u+1+len,[](int i,int j){return dfn[i]<dfn[j];});
		up(i,2,len) {
			int p=lca(u[i-1],u[i]);
			sav[p].pb(u[i]), sav[u[i]].pb(p);
		}
		top=0, f[0][0]=1, dp(rt,0,0);
		up(i,1,k) (ans+=f[top][i])%=P;
		cout << ans << '\n';
		up(i,1,len) tag[u[i]]=0, sav[u[i]].clear();
	}
	return 0;
}
posted @ 2025-11-26 11:20  Hypoxia571  阅读(8)  评论(0)    收藏  举报