【ccpc女生专场】2021女生专场vp总结

Posted on 2023-11-18 21:05  木易meow  阅读(34)  评论(0编辑  收藏  举报

开篇碎碎念

是11.10下午闲来无事vp的,好叭实际是前两天晚上网瘾,一直嘟囔想vp,所以抽了一个时间v了一下,另一方面也是想知道女生赛的大体难度是不是尊嘟如别人所言。5题铜首一个半小时下班,然后美滋滋的去麦麦吃了点饭饭。

K.音乐游戏

赛时先开的K,嗯...因为对字符的亿点点不熟悉所以开出来的实际上有点慢,因为如果按照字符读入的话会有换行在内。
题目含义:有n行,每行6个字符,统计其中'-'出现的次数。

G.3G网络

在K之后开了G,其实刚打开题面感觉有点害怕,因为我高数已经还给老师了...看到数学就头皮发麻,但是看了眼榜还是咬牙看了看题目。
题意:有n个圆形,给出每个圆形的圆心坐标,求在圆形半径趋向于无穷大的时候所有圆形的面积并与所有圆形面积和的比值。
思路:当半径趋向于无穷大时,单个圆形的面积趋向于1,所有的圆形会趋向于重合,所以比值即为1/n;
warning:注意精度问题,遇到精度问题一定要用scanf控制输出位数

D.修建道路

看到题目的时候有在想会不会是直接从右往左两两相连就是最小的,简单在纸上推了推四个点时最大值分别在左中右的情况。发现肯定是尽可能的少包含这个最贵的,但是最便宜的基本没贡献,所以实际上最优解就是两两取最大。

A.公交线路

纯纯纯模拟,用两个指针分别标记往左往右到了哪个站点,然后判断字数是否符合要求就行

I.驾驶卡丁车

这个是我赛时出的最后一道题,看到八个方向的时候:“这不一眼BFS吗,正好这几次vabc写了不少暴搜”,结果一看是模拟,几个不同指令和方向,数组按顺时针记录一下方向。
然后WA6...警钟敲响:速度减小但是不可能为负数

B。攻防演练

赛后补的第一个题目

小Q和小C在比特公司的系统中进行攻防演练,这个系统经过特殊设定,只能接收任何只含有前 \(m\) 个小写英文字母的非空字符串作为输入命令。
小Q事先准备了一个长为 \(n\) 的字符串 \(s = s_1 s_2 \ldots s_n\),为了能够在演练时输入到系统中,这个字符串只会包含前 \(m\) 个小写英文字母。攻防演练一共进行 \(q\) 轮,每轮开始时小Q会选择一个 \(s\) 的非空子串 \(s_{l,r} = s_l s_{l+1} \ldots s_r\) 输入到系统中作为本轮演练的防火墙规则。当防火墙规则配置完成之后,对于任何输入到系统中的命令 \(c\),只要 \(c\)\(s_{l,r}\) 的子序列就会被防火墙拦截。
小C的任务是在每轮演练中,在小Q完成本轮防火墙规则的配置之后,输入一个不被防火墙拦截的命令。为了节约时间,小C想知道每轮演练需要输入的最短字符串的长度是多少。也就是说,小C想找到最小的正整数 \(k\),存在一个长为 \(k\) 的字符串 \(t = t_1 t_2 \ldots t_k\),使得不存在任意一个长为 \(k\) 的序列 \(p_1, p_2, \ldots p_k\) 满足 l<= p1<p2<...<pk<=r 且对每个 \(i=1,2,\ldots,k\) 均有 \(t_i = s_{p_i}\)

实际上就是l~r区间里面最多满足出现了几组小写英文字母,答案在基础上+1;对于多组的优化:倍增

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=2e5+10;
int nxt[26];//存的是 第一个某字母
int dp[MAXN][21];//存的是对于每个位置,下一个可跳 
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int m,n;
	cin>>m>>n;
	string s;
	cin>>s;
	s=' '+s;
	for(int i=0;i<26;i++){
		nxt[i]=n+1;
	} 
	for(int i=n;i>=1;i--){
		int res=0;
		nxt[s[i]-'a']=i;
		for(int j=0;j<m;j++){
			res=max(nxt[j],res);
		}
		if(res>n)res=-1;
		dp[i][0]=res+1;	
	}
	//倍增
	for(int i=n;i>=0;i--){
		for(int j=1;j<=20;j++){
			dp[i][j]=dp[dp[i][j-1]][j-1];
		}
	}
	int ans;
	int q,l,r;
	cin>>q;
	while(q--){
		cin>>l>>r;
		ans=0;
		for(int i=20;i>=0;i--){
			if(dp[l][i] && dp[l][i] <= r + 1){
				ans+=(1<<i);
				l=dp[l][i];
			}
		}
		cout<<ans+1<<endl;
	}
	return 0;
}

C。连锁商店

比特山是一个旅游胜地,它一共有 \(n\) 个景点,按照海拔高度从低到高依次编号为 \(1\)\(n\)。为了更好地帮助游客们欣赏这里的风景,人们在上面搭建了 \(m\) 条缆车路线。每条缆车路线只可能把游客们从某个海拔较低的景点运送到另一个海拔较高的景点。

在每个景点都有一家纪念品连锁商店,其中第 \(i\) 个景点的商店隶属第 \(c_i\) 号公司,两家连锁店 \((i,j)\) 隶属同一公司当且仅当 \(c_i=c_j\)。每家公司都有新客优惠活动,其中第\(i\)家公司对于新客的优惠红包为 \(w_i\) 元,一旦领取了隶属该公司的某家连锁店的一份红包,就不能再领取该公司所有分店的红包。

你正在 \(1\) 号景点,你将会搭乘缆车去往各个景点,每到一个景点,你都可以领取该景点的连锁商店的新客优惠红包(包括 \(1\) 号景点)。当然,同一家公司的红包最多只能领一次。请写一个程序,对于每个可能的终点 \(k\),找到一条从 \(1\) 号景点出发到达 \(k\) 号景点的游览路线,使得可以领取到总金额最多的优惠红包。

一开始一直读假题,一直觉得样例是错的,结果发现第三行是每个公司的优惠券额度,而非每个景点的优惠券额度,换句话说,相同商店开在不同地方的优惠券额度一样。
拓扑排序+状压
状压统计对于开了多家商店的访问情况。
code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=50;
int tot[MAXN],cnt[MAXN],a[MAXN],b[MAXN];
int dp[MAXN][(1<<18)];
vector<int>e[MAXN];
signed main(){
	memset(dp,-1,sizeof dp);
	dp[0][0]=0;
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];//每个景点隶属于哪个公司 
		cnt[a[i]]++;
	}
	int res=0;
	for(int i=1;i<=n;i++){
		if(cnt[i]>1){
			cnt[i]=res++;//将多家商店与1~res对应,方便状压 
		} 
		else cnt[i]=-1;
	}
	for(int i=1;i<=n;i++){
		cin>>b[i];//统计每个公司的优惠券额度 
	}
	int u,v;
	for(int i=1;i<=m;i++){
		cin>>u>>v;
		e[u].push_back(v);
		tot[v]++;//入度 
	}
	e[0].push_back(1);
	tot[1]++;
	queue<int>q;//拓扑排序 
	for(int i=0;i<=n;i++){
		if(tot[i]==0){
			q.push(i);
		}
	}
	while(q.size()){
		u=q.front();
		q.pop();
		for(auto i:e[u]){
			tot[i]--;
			int y=a[i];
			if(tot[i]==0)q.push(i);//拓扑进队 
			if(cnt[y]==-1){//如果这个商店只开了一家 
				for(int j=0;j<(1<<res);j++){
					if(dp[u][j]==-1)continue;
					dp[i][j]=max(dp[i][j], dp[u][j]+b[y]);
				}
			}
			else{
				int p=(1<<cnt[y]);
				for(int j=0;j<(1<<res);j++){
					if(dp[u][j]==-1)continue;
					dp[i][j]=max(dp[i][j],dp[u][j]);//无论选不选这个商店都可以更新一下最大值 
					if(j & p){//已经选过这个商店了 
						continue;
					}
					dp[i][j+p]=max(dp[i][j+p],dp[u][j]+b[y]); 
				}
			}
		}
	}
	for(int i=1;i<=n;i++){
		int mx=0;
		for(int j=0;j<(1<<res);j++){
			mx=max(mx,dp[i][j]);
		}
		cout<<mx<<endl;
	}
	return 0;
}