西北大学2019年春季校赛题解(A-F)

A.辛苦的志愿者

如果m个小姐姐可以完成发气球任务,那么m+1个小姐姐也一定可以完成发气球任务。

二分+优先队列(也可以不用优先队列,直接用数组模拟一个普通队列往后插入就行了)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
#define mp make_pair
#define fi first
#define se second
#define ll long long
int n, m, t, d, ans = 0;
pair<ll,ll> p[maxn];
ll angry[maxn];

bool check(int mid){
	priority_queue <ll,vector<ll>,greater<ll> > q;
	if(!q.empty())	q.pop();
	memset(angry,0,sizeof angry);
	int now = mid;
	bool flag = 1;
	for(int i = 1;i <= n; i++){
		if(now)
			now--,q.push(p[i].fi + t);
		else{
			auto it = q.top();
			q.pop();
			if(it <= p[i].fi)
				q.push(p[i].fi + t);	
			else{
				angry[p[i].se] += it - p[i].fi;
				q.push(it + t);
				if(angry[p[i].se] >= d)	flag = 0;
			}
		}
	}
	return flag;
}
int main(){
	int a,b;
	cin >> n >> m >> t >> d;
	for(int i = 1; i <= n; i++){
		cin >> a >> b;
		p[i] = mp(a,b);
	}
	sort(p + 1, p + 1 + n);
	int l = 1, r = n + 1;
	while(l <= r){
		int mid = (l + r) >> 1;
		if(check(mid))	ans = mid, r = mid - 1;
		else	l = mid + 1;
	}
	cout << ans;
}

(弟弟标程是用的优先队列)

 

B. 北境之都

可以三分!三分比较好想。

但是弟弟标程用的前缀和。枚举最终房间高度,即最低为a,最高为a+k。然后通过前缀和的处理,在logn的时间内完成对答案的计算,并更新ans。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
#define ll long long
ll co[maxn],dqs2[maxn],dqs1[maxn], ans = 1e18;
ll n,k;
ll check(ll a){
	ll tmp = 0;
	ll low = lower_bound(co+1,co+1+n,a) - co - 1;
	ll high = upper_bound(co+1,co+1+n,a+k) - co - 1;
	tmp += low * a * a + dqs2[low] - 2 * a * dqs1[low];
	tmp += (n - high) * (a + k) * (a + k) + dqs2[n] - dqs2[high] - 2 * (a + k) * (dqs1[n] - dqs1[high]);
	return tmp; 
}
int main(){
	cin >> n >> k;
	for(int i = 1; i <= n; i++)
		cin >> co[i];
	sort(co+1,co+1+n);
	for(int i = 1; i <= n; i++)
		dqs2[i] = dqs2[i-1] + co[i] * co[i], dqs1[i] = dqs1[i-1] + co[i];
	for(int i = 1; i + k <= maxn - 5; i++)
		ans = min(ans,check(i));
	cout << ans;
}

 

C 景字棋

比较毒瘤的题。。大模拟,要考虑的情况很多。但是已经下了六步,降低了难度,可以直接判断双方是否能一步胜利(即A下一步,B再下一步能否结束),不能的话就是平局。

就是不合法比较难判,比如黑棋下三步已经胜利,白棋下了三步,这当然是不合法的。因为黑棋先下,三步胜利之后就结束了。

正确的出题方式应该是只判断是否合法。。再判断输赢真的毒瘤,我接锅。

 

D 今年寒假不AC

弟弟标程非用N²做,实际可以直接记录当前状态线性递推。

#include <bits/stdc++.h>
using namespace std;
long long n, w2[10], w3[10], a[2005], dp[2005], num[10][2005];
char s[2005];
int cal(int x, int y){
	if(y < 3) return 0;
	if(w2[x] * 3 >= w3[x]) return (y / 3) * w2[x];
	return w3[x] * (y / 9) + w2[x] * ((y % 9) / 3);
}
int main(){
	scanf("%lld", &n);
	for(int i = 1; i <= 5; i++) scanf("%lld", &w2[i]);
	for(int i = 1; i <= 5; i++) scanf("%lld", &w3[i]);
	scanf("%s", s + 1);
	for(int i = 1; i <= n; i++) a[i] = (s[i] - 'A') + 1;
	for(int j = 1; j <= 5; j++) for(int i = 1; i <= n; i++) num[j][i] = num[j][i - 1] + (a[i] == j);
	for(int i = 1; i <= n; i++) for(int j = 1; j <= i; j++) if(a[j] == a[i]){
		dp[i] = max(dp[i], dp[j - 1] + cal(a[i], num[a[i]][i] - num[a[i]][j - 1]));
	}
	printf("%lld", dp[n]);
	return 0;
}

于是我选用了现场赛中NWPU的哥哥代码作为标程。。

 

E. NE的挑战Ⅱ

带删除的并查集,对于删除操作,新开一个结点映射被删除的点即可。

#include <bits/stdc++.h>
using namespace std;
#define N 4000005
int n,m,fa[N],to[N],o,x,y,tot,a[N],b[N],cnt,gg[N],sz[N];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void mer(int x,int y){int a=find(to[x]),b=find(to[y]);if(a==b) return;fa[b]=a;sz[a]+=sz[b];sz[b]=0;}
void upd(int x,int y){sz[find(to[x])]--;to[x]=++cnt;sz[cnt]=1;fa[cnt]=cnt;mer(x,y);}
int main(){
	scanf("%d%d",&n,&m);cnt=n;
	for(int i=1;i<=n;i++) fa[i]=i,to[i]=i,sz[i]=1;
	for(int i=1;i<=m;i++){
		scanf("%d%d",&o,&x);if(o!=3) scanf("%d",&y);
		if(o==5){a[++tot]=x,b[tot]=y;continue;}
		if(o==1) mer(x,y);
		if(o==2) upd(x,y);
		if(o==3) printf("%d\n",sz[find(to[x])]-1);
		if(o==4) puts(find(to[x])==find(to[y])?"Yes":"No");
	}
	for(int i=1;i<=tot;i++) if(find(to[a[i]])==find(to[b[i]])) gg[find(to[a[i]])]=1;
	int mx=-1;
	for(int i=1;i<=n;i++)
		if(!gg[find(to[i])]) mx=max(mx,sz[find(to[i])]);
	printf("%d\n",mx);
}

为了减少博客长度,选了一个压行怪的代码。

不过可读性还可以,毕竟上面都是并查集板子,压行就压行吧。。

F. 三生三世

递归回溯+组合数学

枚举这一位填哪个字母,假如这个字母比原串的字典序大,返回0,比原串字典序小,则返回其余字母的排列数。如果相等,再继续往后dfs。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#pragma comment(linker, "/STACK:102400000,102400000")
const ll mod = 1e9 + 7;
const int maxn = 2e5 + 5;
string str1,str2,str;
int num[30], n;
ll F[maxn], Finv[maxn], inv[maxn];//F是阶乘,Finv是逆元的阶乘 
void init(){
    inv[1] = 1;
    for(int i = 2; i < maxn; i ++){
        inv[i] =(mod - mod / i) * 1ll * inv[mod % i] % mod;
    }
    F[0] = Finv[0] = 1;
    for(int i = 1; i < maxn; i ++){
        F[i] = F[i-1] * 1ll * i % mod;
        Finv[i] = Finv[i-1] * 1ll * inv[i] % mod;
    }
}
ll comb(int n, int m){//comb(n, m)就是C(n, m) 
    if(m < 0 || m > n) return 0;
    return F[n] * 1ll * Finv[n - m] % mod * Finv[m] % mod;
}
ll dfs(int len, int now){
	if(len == n - 1)	return 0;//如果走到字符串最后一位,返回 
	if(len != -1 && now < str[len] - 'A'){//如果当前位置已经比字符串字典序小,后面就可以任意摆放
	//用组合数学的方法算出后面可以摆放出几种 
		int need = n - len - 1;
		ll tmp = 1;
		for(int i = 0; i < 26; i++)
			if(num[i])
				tmp = (tmp * comb(need, num[i])) % mod, need -= num[i];
		return tmp;
	}
	ll tmp = 0;
	for(int i = 0; i < 26; i++){
		if(i <= str[len+1] - 'A' && num[i]){
			num[i]--;
			tmp = (tmp + dfs(len + 1, i)) % mod;//尝试选择i字符,进入下一层递归 
			num[i]++;//回溯 
		}
	}
	return tmp;
}
ll solve(string strk){
	memset(num,0,sizeof num);
	str = strk;
	for(int i = 0; i < n; i++)
		num[str[i]-'A']++;//统计每种字符出现次数 
	return dfs(-1,30);
}
int main(){                    
	init();
	cin >> n;
	cin >> str1 >> str2;
	cout << (solve(str1) - solve(str2) + mod) % mod;	
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的纺织品企业财务管理系统,源码+数据库+毕业论文+视频演示 在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以,对纺织品企业财务信息管理的提升,也为了对纺织品企业财务信息进行更好的维护,纺织品企业财务管理系统的出现就变得水到渠成不可缺少。通过对纺织品企业财务管理系统的开发,不仅仅可以学以致用,让学到的知识变成成果出现,也强化了知识记忆,扩大了知识储备,是提升自我的一种很好的方法。通过具体的开发,对整个软件开发的过程熟练掌握,不论是前期的设计,还是后续的编码测试,都有了很深刻的认知。 纺织品企业财务管理系统通过MySQL数据库与Spring Boot框架进行开发,纺织品企业财务管理系统能够实现对财务人员,员工,收费信息,支出信息,薪资信息,留言信息,报销信息等信息的管理。 通过纺织品企业财务管理系统对相关信息的处理,让信息处理变的更加的系统,更加的规范,这是一个必然的结果。已经处理好的信息,不管是用来查找,还是分析,在效率上都会成倍的提高,让计算机变得更加符合生产需要,变成人们不可缺少的一种信息处理工具,实现了绿色办公,节省社会资源,为环境保护也做了力所能及的贡献。 关键字:纺织品企业财务管理系统,薪资信息,报销信息;SpringBoot
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值