首页 > 其他分享 >5.8-5.14

5.8-5.14

时间:2023-05-15 20:23:15浏览次数:56  
标签:子串 QAQ 5.8 void cin int num 5.14

C1. Pokémon Army (easy version)

Problem - 1420C1 - Codeforces

线性dp

呃啊啊啊啊啊啊啊太久没写dp了,下周开始要把重点放到算法上

意识到是个dp后就很简单了,状态转移方程也很好写出

\[\begin{cases}f[i][0]\ =\ max(f[i-1][0],\ f[i-1][1]+num[i]\\f[i][1]\ = \ max(f[i-1][1],\ f[i-1][0]+num[i]\ \end{cases} \]

然后就快乐地开始dp吧~

int n, m, f[N][2], num[N];

void QAQ(){
	cin >> n >> m;
	for(int i = 1; i <= n; i ++) cin >> num[i];
	f[0][0] = f[0][1] = 0;
	for(int i = 1; i <= n; i ++){
		f[i][0] = max(f[i - 1][0], f[i - 1][1] + num[i]);
		f[i][1] = max(f[i - 1][1], f[i - 1][0] - num[i]);
	}
	cout << max(f[n][0], f[n][1]) << endl;
}

A. Banana

Problem - 335A - Codeforces

构造

读了假题

​ 注意到题目中每次购买的贴纸数可以是不连续的,这为我们省下了很多功夫。

​ 其次注意到题目字符串长度小于1000,那么我们可以暴力枚举要买贴纸的次数,反推出需要原始子串的长度,看是否符合要求,符合要求就输出。

​ 当然,如果使用二分会是更优的解法。(虽然最后运行时间没有差很多)

int n, k; 
map<char, int> mp;
string s;

void QAQ(){
	cin >> s >> k;
	n = s.size();
	int cnt = 0;
	for(auto ch : s){
		if(!mp[ch]) cnt ++;
		mp[ch] ++; 
	}
	if(cnt > k) {
		cout << "-1\n";
		return ;
	}
	int ans;
	for(int i = 1; i <= 1000; i ++){
		int sum = 0;
		for(char j = 'a'; j <= 'z'; j ++){
			sum += (mp[j] + i - 1) / i; 
		} 
		if(sum <= k){
			ans = i;
			break;
		}
	} 
	cout << ans << endl;
	int len = 0;
	for(char i = 'a'; i <= 'z'; i ++){
		int t = (mp[i] + ans - 1) / ans;
		len += t;
		while(t --){
			cout << i;
		}
	} 
	while(len < k){
		cout << 'a';
		len ++;
	}
	cout << endl;
}
int n, m;
map<char, int> mp;
string s;
//二分
bool check(int x){
	int res = 0;
	for(int i = 'a'; i <= 'z'; i ++){
		res += (mp[i] + x - 1) / x;
	} 
	return res > m;
}

void QAQ(){
	cin >> s;
	n = s.size();
	s = " " + s;
	cin >> m;
	int cnt = 0;
	for(int i = 1; i <= n; i++){
		if(!mp[s[i]]) cnt ++;
		mp[s[i]] ++; 
	} 
	if(cnt > m){
		cout << "-1\n";
		return ;
	}
	int r = n + 1, l = 0;
	while(l + 1 < r){
		int mid = l + r >> 1;
		if(check(mid)){
			l = mid;
		}
		else{
			r = mid;
		}
	}
	cout << r << endl;
	cnt = 0;
	for(int i = 'a'; i <= 'z'; i++){
		int tmp = (mp[i] + r - 1) / r;
		cnt += tmp;
		while(tmp --){
			cout << (char)i;
		}
	}
	while(cnt < m){
		cout << "a";
		cnt ++;
	}
	cout << endl;
}

C. Element Extermination

Problem - 1375C - Codeforces

构造,结论

​ 结论就是如果队头元素大于队尾元素,就一定不可以。

​ 在洛谷上看到的题解,感觉相对比较好理解,记录一下。

​ 假设当前有\(a_1,...,a_n\)个数,由于每次删去的条件是\(a_i<a_{i + 1}\),所以为了增加删去最后一个元素的可能性,我们要尽可能地在前面删去的时候留下靠前面且较小的数。

​ 那么对于第1个数,如果\(a_1<a_2\),那么删去\(a_2\),留下\(a_1\),反之我们只可能尝试替换\(a_2\),也将留下\(a_1\),所以在最后一次操作之前,\(a_1\)始终能被保留。

​ 同理,对于最后一个数,如果\(a_{n-1}<a_n\),为了让最后一个数尽可能大,我们选择保留\(a_n\),反之,我们就尝试替换\(a_{n-1}\),使得之前能被满足,所以\(a_n\)也会被一直保留。

​ 那么按照上面的思路,不考虑中间的元素是否能被删完,一串数能否被删完的关键在于它的首元素和尾元素能否被删去(即我们现在只关注每次操作的最后一步)

​ 最终得到结论,如果\(a_1<a_n\),那么就可以删完,否则就不能删完。

​ 代码很简单就不给出了。

B. Find The Array

Problem - 1463B - Codeforces

构造

有两种不同的思路(当然都是看了题解后得到的思路)

  • 变1构造

    ​ 什么样的串符合它的所有相邻的数都能被彼此整除呢?我们能想到的最简单的数组就是一串全为1的数列,但是很明显,由于题目有着\(2\sum_{i=1}^n|a_i-b_i|\leq\sum_{i=1}^na_i\),所以我们不可能让所有元素都变成1。

    ​ 那么该怎么去构造呢?既然不能让所有元素都变成1,事实上间隔地把数变成1也是可以满足我们的要求的。那么这种方法是否符合我们上面的式子呢?我们会很惊奇地发现,如果偶数位上数的和较小,我们就把偶数位变成1,否则就把奇数位变成1,最终都是可以满足题目的要求的。

    int n, num[N]; 
    
    void QAQ(){
    	cin >> n;
    	int a = 0, b = 0;
    	for(int i = 1; i <= n; i++){
    		cin >> num[i];
    		if(i & 1) a += num[i] - 1;
    		else b += num[i] - 1;
    	}
    	if(a < b){
    		for(int i = 1; i <= n; i ++){
    			if(i & 1) cout << "1" << " ";
    			else cout << num[i] << " ";
    		}
    	}
    	else{
    		for(int i = 1; i <= n; i ++){
    			if(i & 1) cout << num[i] << " ";
    			else cout << "1" << " ";
    		}
    	}
    	cout << endl;
    }
    
  • 2的k次方构造

    ​ 我们仍然着眼于题目给出的第二个性质,即\(2\sum_{i=1}^n|a_i-b_i|\leq\sum_{i=1}^na_i\)。

    ​ 如果我们一项项来看这条式子,那么就会得到\(2*|a_i-b_i|\leq a_i\),也即是\(b_i \sub [\frac{a_i}2,\ 2a_i]\)。仔细推一下就会发现,一定存在一个\(2^k\)在上面的范围内,使得上面的等式成立。而且对于每一对\(2^t\)和\(2^k\),它们两个一定可以满足整除的关系。

    ​ 由于\(2^k\)次方可以简单地通过1左移k次得到,我们就不用预处理。只需要从小到大枚举k,找到第一个 能使上述等式成立的输出就可以了。

    int  n, num[N];
    
    void QAQ() {
    	cin >> n;
    	for(int i = 1; i <= n; i ++) cin >> num[i];
    	for(int i = 1; i <= n; i ++){
    		int k = 1;
    		while(2 * abs(k - num[i]) > num[i]) k <<= 1;
    		cout << k << " ";
    	}
    	cout << endl;
    }
    

C. 0689

题目详情 - 4128 0689 (pintia.cn)

题意:

​ 有一串子串只包含'0','6','8','9'四种字符。可以选择任意长度的子串进行180°翻转,使得其左右位置调换的同时'0'->'0','6'->'9','9'->'6','8'->'8'。问每次进行一次上述操作,最多可以得到多少个不同的字串。

思路:

一开始以为是找回文子串,跟队友口胡了一个Manacher的做法感觉很合理,但是WA了,后面被另一个队友批判原来做法没有排除改变后相同的情况。最后看了题解,感觉想法非常玄妙啊。

​ 如果不考虑重复的情况,那么对于长度为n的字符串,可以选择左右区间产生子串的个数就是\(\frac{n(n + 1)}{2}\)。对于选择的子串,如果我们选择如"0xxxx0"、"6xxxx9"、"8xxx8"等翻转后不会变化的数字为左右开头,实际上会与我们选择其除去两端后的字符串翻转后重复。为了排除这些重复,我们需要减去以上述情况开头的选择

void QAQ() {
	string s;
	cin >> s;
	n = s.size(); 
	int a = 0, b = 0, c = 0, d = 0;
	for(auto x : s){
		if(x == '0') a ++;
		else if (x == '6') b ++;
		else if(x == '8') c ++;
		else if(x == '9') d ++;
	}
	int ans = n * (n + 1) / 2 + 1;
	ans -= a * (a + 1) / 2;//以0为左右端点的重复选择
	ans -= b * d;//以69为左右端点的重复选择
	ans -= c * (c + 1) / 2;//以8为左右端点的重复选择
	if(b == n || d == n) ans --;
    //如果全为'6'或'9',无法构造出原串,所以要减去
	cout << ans << endl;
}

​ 特别的,需要注意实际上原串并不是答案的一部分,除非我们能通过翻转构造回原串(即选择翻转后不变的子串),但这些子串在后面去重的时候会被丢弃,所以实际上我们需要在计算结果时+1。但是当一串里面只存在'6'或是'9'时,无论我们怎么选择都无法得到原来的串,所以需要减去之前加上的1。

标签:子串,QAQ,5.8,void,cin,int,num,5.14
From: https://www.cnblogs.com/woods4325/p/17402968.html

相关文章

  • 2023.5.14
    1#include<iostream>2usingnamespacestd;3#include<vector>4voidprintVector(vector<int>&v)5{6for(vector<int>::iteratorit=v.begin();it<v.end();it++)7{8cout<<*it<<......
  • 编程一小时2023.5.14
    #include<iostream>#include<vector>usingnamespacestd;boolcmp(vector<int>&A,vector<int>&B){if(A.size()!=B.size())returnA.size()>B.size();for(inti=A.size()-1;i>=0;i--)if(A[i]!=B[i])re......
  • 2023.5.14——软件工程日报
    所花时间(包括上课):6h代码量(行):0行博客量(篇):1篇今天,上午学习,下午学习。我了解到的知识点:1.了解了一些数据库的知识;2.了解了一些python的知识;3.了解了一些英语知识;5.了解了一些Javaweb的知识;4.了解了一些数学建模的知识;6.了解了一些计算机网络的知识;......
  • 打卡5.8——勾股数
    1.问题描述求100以内所有的勾股数所谓勾股数,是指能够构成三角形三条边的三个正整数。2.问题分析勾股数,要符合a^2+b^2=c^2,而且任意两条边的和大于第三条边这就要用到sqrt函数,就相当于不用平方了c=(int)sqrt(a*a+b*b);if(c*c==a*a+b*b&......
  • 5.14
    #include<iostream>#include<string>usingnamespacestd;classMyprint{public:voidoperator()(stringtext){cout<<text<<endl;}};voidtest1(){Myprintmyprint;myprint("helloworld");}classMyadd{public:intoperato......
  • 建民打卡日记5.14
    一、问题描述一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下:首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};然后将计算的和对11取模得到值Z;最后按照以下关系对应Z值与校验码M的值:Z:012345678910M:10X987......
  • 5.14
    classBase{public:intfn1()const{return1;}intfn2()const{return2;}};classDerived:privateBase{public:intfn1(){returnBase::fn1();};intfn2(){returnBase::fn2();};};intmain(){Deriveda;a.fn1();return0;......
  • qt5.14.modbus rtu源码,运行无问题! ---Modbus具有两种串行
    qt5.14.modbusrtu源码,运行无问题!---Modbus具有两种串行传输模式:分别为ASCII和RTU。此源代码是RTU。Modbus是一种单主站的主从通信模式,Modbus网络上只能有一个主站存在,主站在Modbus网络上没有地址,每个从站必须有唯一的地址,从站的地址范围为0-247,其中0为广播地址,从站的实际地址范......
  • 2023.5.14编程一小时打卡
    一、问题描述:计算点到直线的距离。首先设计一个点类Point,它有2个私有数据成员x和y,表示点的坐标。另一个类为直线类Line,它有3个私有数据成员a,b和c,表示直线方程ax+by+c=0。这两个类中都说明了一个友元函数dist,用于计算一个点到直线的距离。点(x.y)到直线ax+by+c=0的距离d的......
  • 5.14打卡
    问题描述:比较两个分数的大小二、设计思路:要求通分后的最简公分母,即求两分母的最小公倍数。求最小公倍数的前提是求出两数的最大公约数,最大公约数的求解采用辗转相除的方法,步骤如下:(1)用较大的数m除以较小的数n,得到的余数存储到变量b中;b=m%n;(2)上一步中较小的除数n和得出的余数b......