2017 hdu多校 第八场

版权声明:https://github.com/godspeedcurry 欢迎加好友哦 https://blog.csdn.net/qq_38677814/article/details/82952403

今天读错了好多题 贡献为负 对不起队友。。

Killer Names
注意MOD不要少些几个 中间变量会爆long long
dp[i][j]=dp[i-1][j]*j+dp[i-1][j-1]*j;
这个转移
前i-1 有j个字母了 那我当前位置随便填写前j中的一个
+
前i-1有j-1个字母了 那我当前位置写一个新的+之前j-1挑一个替换成新的然后当前位置写那个旧的

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MOD=1e9+7;
ll fact[2048][2048];
ll C(ll n,ll m){
	if(m==0||n==m) return 1;
	if(fact[n][m]) return fact[n][m];
	return fact[n][m]=(C(n-1,m)+C(n-1,m-1))%MOD;
}
ll dp[2024][2024];
ll solve(ll n,ll m){
	memset(dp,0,sizeof(dp));
	//dp[i][j] 表示到第i个用了j个字母的方案数
	for(int i=1;i<=n;i++) dp[i][1]=1;	
	for(ll i=1;i<=n;i++){
		for(ll j=2;j<=min(i,m);j++){
			dp[i][j]=dp[i-1][j]*j%MOD+dp[i-1][j-1]*j%MOD;
			dp[i][j]%=MOD;
		}
	}
	ll ans=0;
	for(ll i=1;i<=min(n,m);i++){
		for(ll j=1;i+j<=m&&j<=n;++j){
			(ans+=dp[n][i]*dp[n][j]%MOD*(C(m,i)*C(m-i,j)%MOD)%MOD)%=MOD;
		}
	}
	return ans;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		ll n,m;
		scanf("%lld%lld",&n,&m);
		printf("%lld\n",solve(n,m));
	}
	return 0;
}

这道题读错好几次。。漏看了条件导致题目变难系列。。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MOD=1e9+7;
ll a[10000];
char c[10000];
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		ll n,m;
		scanf("%lld%lld",&n,&m);
		for(int i=1;i<=n;++i) scanf("%lld",a+i);
		for(int i=1;i<=n;++i) cin>>c[i];
		ll up,low;
		up=low=0;
		for(int i=1;i<=n;++i){
			if(c[i]=='L') up+=a[i];
			else if(c[i]=='D') low-=a[i];
			else up+=a[i],low-=a[i];
		}

		if(m>=low&&m<=up) puts("yes");
		else puts("no");
	}
	return 0;
}

树上启发式合并+树状数组
PE? 要多打一个空格才能过。。 题目的锅吧

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MOD=1e9+7;
#define MAXN 102000
#define pb push_back
#define lowbit(i) (i&(-i))
vector<int>G[MAXN];
int n,tot;
ll val[MAXN],a[MAXN],sum[MAXN],lson[MAXN],rson[MAXN],num[MAXN],ans[MAXN],pos[MAXN],siz[MAXN];
//num[MAXN] 出现了哪些权值的点
//sum[MAXN] 出现点的权值
ll SUM;
void init(){
	SUM=0;
	for(int i=1;i<=n;++i) G[i].clear();
	for(int i=1;i<=n;++i) sum[i]=num[i]=0;
	for(int i=1;i<=n;++i) lson[i]=rson[i]=siz[i]=0;
}
ll getsum(ll *arr,ll x){
	ll ret=0;
	for(ll i=x;i;i-=lowbit(i)){
		ret+=arr[i];
	}
	return ret;
}
void update(ll *arr,ll x,ll val){
	for(ll i=x;i<=tot;i+=lowbit(i)){
		arr[i]+=val;
	}
}
void dfs(int u,int fa){
	siz[u]=1;
	for(int i=0;i<G[u].size();++i){
		int to=G[u][i];
		if(to==fa) continue;
		if(!lson[u]) lson[u]=to;
		else rson[u]=to;
		dfs(to,u);
		siz[u]+=siz[to];
	}
	if(lson[u]&&rson[u]&&siz[lson[u]]>siz[rson[u]]) swap(lson[u],rson[u]);
}
void add(int id){
	SUM+=(getsum(num,tot)-getsum(num,id)+1)*val[id];//额外加上(比他大的个数+1)*自己
	SUM+=getsum(sum,id);//比他小的再加一次 
	update(num,id,1);//id 出现 记录一下
	update(sum,id,val[id]);//权值出现
}
void del(int id){
	update(num,id,-1);//id消失 
	update(sum,id,-val[id]);//权值消失
	SUM-=(getsum(num,tot)-getsum(num,id)+1)*val[id];//减掉他产生的贡献值
	SUM-=getsum(sum,id);//减掉之前数的偏移量
}
void clr(int u){
	del(pos[u]);
	if(lson[u]) clr(lson[u]);
	if(rson[u]) clr(rson[u]);
}
void merge(int u){
	add(pos[u]);
	if(lson[u]) merge(lson[u]);
	if(rson[u]) merge(rson[u]);
}
void solve(int u){
	if(!lson[u]){
		ans[u]=a[u];
		add(pos[u]);
		return;
	}
	solve(lson[u]);
	if(rson[u]){
		clr(lson[u]);
		solve(rson[u]);
		merge(lson[u]);
	}
	add(pos[u]);
	ans[u]=SUM;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		init();
		for(int i=1;i<=n;++i) scanf("%lld",a+i),val[i]=a[i];
		sort(val+1,val+1+n);
		tot = unique(val+1,val+1+n)-val-1;//去重
		for(int i=1;i<=n;++i) pos[i]=lower_bound(val+1,val+tot+1,a[i])-val;//离散化
		for(int i=1;i<n;++i){
			int u,v;
			scanf("%d%d",&u,&v);
			G[u].pb(v);
			G[v].pb(u);
		}
		dfs(1,0);//标记 父亲节点 左儿子的siz较小 
		solve(1);//处理答案
		for(int i=1;i<=n;++i) printf("%lld ",ans[i]);
		printf("\n");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38677814/article/details/82952403