#week3

第一题快快变大

给定一个长度为 n的数组 a1,a2,…,an,接下来进行 n−1次操作每次选择一个下标 x,将 ax 和 ax+1合并成ax×ax+1mod1000003,并且你会获得 (ax−ax+1)2的分数。所以每次操作后,数组的长度将会减 1,当最后只剩下一个元素时停止操作。输出最终能获得的最大分数。
输入格式
第一行一个数字 n接下来一行 n个整数 a1,a2,…,an
输出格式
一个数,表示答案。
样例输入
3
1 2 3
样例输出
26
首先,不存在按大小顺序来和并的简单规律,有很多简单的反例可以证明,就不说了,之后考虑dp,dp[i][j]表示从i到j这个区间内可以得到的最大分数,之后按照dp的思想,从区间长为2的区间推到n,先假设我们已经推完所有区间长为3的区间,对于区间长为4的,如dp[1][4],要在三种情况里取大,
1.先合12,34,再合并;
2.先13,再和4;
3.先24,再合1。
对于任意一段区间,合完后他们等于区间内所有数之积,所以dp[i][j]=max(dp[i][j],dp[i][k] + dp[k + 1][j] + (cheng[i][k]-cheng[k+1][j])^2),cheng表示i到j乘积,k从i+1递增到i+len-2。

#include <bits/stdc++.h>
using namespace std;
const int mod = 1000003;
int ori[400];
long long cheng[400][400];
long long dp[400][400] = { 0 };
int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> ori[i];
	}
	for (int i = 1; i <= n; i++) {
		cheng[i][i] = ori[i];
		for (int j = i+1; j <= n; j++) {
			cheng[i][j] = (cheng[i][j-1] * ori[j]) % mod;
		}
	}
	for (int len = 2; len <= n; len++) {
		for (int i = 1; i + len-1 <= n; i++) {
			int j=i+len-1;
			for(int k=i;k<j;k++){
			dp[i][j]=max(dp[i][j],dp[i][k] + dp[k + 1][j] + (long long)pow((cheng[i][k]-cheng[k+1][j]),2));
			}
		}
	}
	cout << dp[1][n];
}

饿饿 饭饭2

题面http://oj.daimayuan.top/problem/561
第一版想法,求所有数的最大公约数,之后每个数除公约数,之后对2和3取余,若有一个为0,就能过,但发现,对于这组数据,20,1,4公约数是1,20取余2为0,但1和4明显乘不出20,所以要修改为每个数除公约数后的商只有2和3的指数构成,于是对于商,我们先除尽里面的2和3,若剩下来的数不为1,代表这个数不行。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5 + 10;
ll ori[maxn];
ll  yue(ll a, ll b)
{
	while (1)
	{
		ll t = a % b;
		if (t == 0)
		{
			break;
		}
		else
		{
			a = b;
			b = t;
		}
	}
	return b;
}
int find(int x){
	while (x%2==0)
	{
		x/=2;
	}
	while (x%3==0)
	{
		x/=3;
	}
	if(x!=1){
		return 1;
	}else{
		return 0;
	}
}
int main() {
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		for (int i = 0; i < n; i++) {
			cin >> ori[i];
		}
		if (n == 1) {
			cout << "YES" << endl;
			continue;
		}
		ll maxyue = yue(ori[0],ori[1]);
		for (int i = 2; i < n; i++) {
			if (ori[i] % maxyue == 0) {
				continue;
			}
			else {
				maxyue = yue(maxyue, ori[i]);
			}
		}
		//cout<<maxyue<<endl;
		// if (maxyue == 1) {
		// 	cout << "NO" << endl;
		// 	continue;
		// }
		for (int i = 0; i < n; i++) {
			int temp = ori[i] / maxyue;
			if(temp==1)continue;
			if (find(temp)) {
				cout << "NO" << endl;
				goto end;
			}
		}
		cout << "YES" << endl;
	end:;
	}
}

第三题

题面http://oj.daimayuan.top/problem/563
想出两个方法,第一个卡一个点tle,感觉改改应该能过
1.dp[i][j]记录i到j的个数,总结出来的转移方程是len是区间长dp[i][i+len-1]=dp[i][i+len-2] + dp[i+1][i+1+len-2] - dp[i+1][i+1+len-3]+ geshu(i, len);前两项表示长为len-1的两个个数,如求1到4,前两项就是1到3和2到3的个数,第三项是前两项重合的个数,第四项从1到4的所有字母个数,对于geshu,基于前缀和,想出来一个方法,用一数组zimu[n][26]记录到第i个字符各个字母有多少个,之后一个区间的字符数等于区间末的所有字母数-区间头的所有字母数。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int zimu[maxn][26];
int dp[3][maxn];
int geshu(int j, int len) {
	int num = 0;
	if (j == 0) {
		for (int i = 0; i < 26; i++) {
			if (zimu[j + len - 1][i]> 0) {
				num++;
			}
		}
	}
	else {
		for (int i = 0; i < 26; i++) {
			if (zimu[j + len - 1][i] -zimu[j - 1][i] > 0) {
				num++;
			}
		}
	}
	return num;
}
int main() {
	//ios::sync_with_stdio(false);
	//cin.tie(0);
	//cout.tie(0);
	char a[maxn];
	scanf("%s", &a);
	int long_a = strlen(a);
	for (int i = 0; i < long_a; i++) {
		zimu[i][a[i] - 'a']++;
		copy(begin(zimu[i]), end(zimu[i]), begin(zimu[i + 1]));
	}
	int now = 2;
	int last = 1;
	int lastlast = 0;
	for (int i = 0; i < long_a; i++) {
		dp[last][i] = 1;
		dp[lastlast][i] = 0;
	}
	int num = 2;
	while (num <= long_a)
	{
		for (int i = 0; i < long_a - num + 1; i++) {
			dp[now][i] = dp[last][i] + dp[last][i + 1] - dp[lastlast][i + 1] + geshu(i, num);;
		}
		lastlast = last;
		last = now;
		num++;
		now = now == 2 ? 0 : now + 1;
	}
	cout << dp[last][0];
}

第二种,贡献的想法
pre[n]存的是与第i个字符相同的前面最近的下标,没有为0,
下标从1开始,以ababcabc为例,由于不限制只出现一次,所以从i字符一直到结束的所有子串都会被贡献一个第i个字符。第一个字母a对以下标1开头到结束的所有子串都有贡献,而对于第二个字母a而言,从下标2和下标3开头的所有子串,a都有贡献,这些子串都至少有一个a,但不能有下标1开头的,因为下标1开头的已经贡献过了,所以第i个字母贡献给了(i-pre[i])(n+1-i)个子串,这些子串的字母数都加1。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int main() {
	int pre[maxn] = { 0 };
	int now[26] = { 0 };
	string a;
	cin >> a;
	int len = a.length();
	a = "0" + a;
	for (int i = 1; i <= len; i++) {
		pre[i] = now[a[i] - 'a'];
		now[a[i] - 'a'] = i;
	}
	long long sum = 0;
	for (int i = 1; i <= len; i++) {
		sum += (i - pre[i]) * (len + 1 - i);
	}
	cout << sum;
}

第四题 蒟蒻

题面http://oj.daimayuan.top/course/11/problem/605
万能的优先队列和map!kami!

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int again_w[maxn];
int again_t[maxn];
priority_queue<int, vector<int>, greater<int>> sw;
priority_queue<int, vector<int>, greater<int>> st;
map<int, int> tw;
map<int, int>wt;
long long sum = 0;
int main() {
	int n;
	cin >> n;
	while (n--)
	{
		int op;
		cin >> op;
		if (op == 1) {
			int w, t;
			cin >> w >> t;
			if (again_w[w] == 1 || again_t[t] == 1) {
				continue;
			}
			sum += w;
			again_t[t] = 1;
			again_w[w] = 1;
			tw[t] = w;
			wt[w] = t;
			sw.push(w);
			st.push(t);
		}
		else if (op == 2) {
			int top = sw.top();
			while (again_w[top]==0)
			{
				sw.pop();
				top = sw.top();
			}
			again_w[top] = 0;
			again_t[wt[top]] = 0;
			sw.pop();
			sum -= top;
		}
		else {
			int top = st.top();
			while (again_t[top] == 0)
			{
				st.pop();
				top = st.top();
			}
			again_t[top] = 0;
			again_w[tw[top]] = 0;
			st.pop();
			sum -= tw[top];
		}
	}
	cout << sum;
	return 0;
}

第五题 锦标赛

题面http://oj.daimayuan.top/course/11/problem/80
我们把数列从小到大排一个序,对于第i个数,他获胜的理想情况是,比他小的都输给他,比他大的数经过比赛后,只有第一个比他大的数最终险胜,他两比赛,之后i赢了i+1;所以遍历循环,对于第i个数,若与i+1的差大于k,则i之前包括i都不可能获胜,num=0,否则num++;第n个数由于和0比,比大于k,所以终点不用考虑。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
long long ori[maxn];
int main() {
	long long k;
	int n;
	cin >> n >> k;
	for (int i = 0; i < n; i++) {
		cin >> ori[i];
	}
	sort(ori, ori + n);
	long long num = 0;
	for (int i = 0; i < n; i++) {
		if (ori[i + 1] - ori[i] <= k) {
			num++;
		}
		else {
			num = 0;
		}
	}
	cout << num;
}

第六题 可重排列

题面http://oj.daimayuan.top/course/11/problem/113
next_permutation为什么是神!还是字典序,笑死。

#include<bits/stdc++.h>
using namespace std;
int ori[11];
int ori1[100];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n;
	cin >> n;
	int sum = 0;
	for (int i = 1; i <= n; i++) {
		cin >> ori[i];
		sum += ori[i];
	}
	int num = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j < ori[i]; j++) {
			ori1[num++] = i;
		}
	}
	do {
		for (int i = 0; i < sum; i++) {
			printf("%d ", ori1[i]);
		}
		printf("\n");
	} while (next_permutation(ori1, ori1 + sum));

}

第七题 进制转换

题面http://oj.daimayuan.top/problem/612
不会还有人不会进制转换吧,不会吧

#define _CRT_SECURE_NO_WARNINGS
#define ll long long
#include<bits/stdc++.h>
using namespace std;
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	ll sum=0;
	for (int i = 0; i < n; i++) {
		int t;
		char a[100];
		scanf("%d%s", &t, &a);
		ll now = 0;
		int len = strlen(a);
		for (int j = len - 1; j >= 0; j--) {
			if (a[j] >= '0' && a[j] <= '9') {
				now += pow(t, len - j - 1) * (a[j] - '0');
			}
			else if (a[j] >= 'a' && a[j] <= 'z') {
				now += pow(t, len - j - 1) * (a[j] - 'a' + 36);
			}
			else {
				now += pow(t, len - j - 1) * (a[j] - 'A' + 10);
			}
		}
		sum += now;
	}
	string ans;
	while (sum > 0) {
		int temp = sum % m;
		if (temp > 35) {
			ans += 'a' + temp-36;
		}
		else if(temp>9) {
			ans += 'A' + temp - 10;
		}
		else {
			ans += '0' + temp;
		}
		sum /= m;
	}
	reverse(ans.begin(), ans.end());
	cout << ans;
}

第八题 循环子串

题面http://oj.daimayuan.top/problem/552
首先是对于循环的处理,我直接在原序列后面又加了一个原序列,ccca变成cccaccca这样,之后是判完全循环,按照题意对于任意子串都能在变化后的序列里找到子串,根据这个特征想到了回文串,只有变化后的序列里有一个长于n的,从开头开始的回文串,就一点是完全循环的,但不确定还有没有其他情况也满足,之后啊,试试发现过了,

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

int main() {
	int t;
	scanf("%d", &t);
	for (int i = 0; i < t; i++) {
		int n;
		char ori[1010];
		char now[2020];
		scanf("%d%s", &n, &ori);
		copy(ori, ori + n, now);
		copy(ori, ori + n, now + n);
		bool no = 0;
		for (int j = n; j < n + n; j++) {
			no = 0;
			for (int i = 0; i < j / 2; i++) {
				if (now[i] != now[j - i - 1]) {
					no = 1;
					break;
				}
			}
			if (!no) {
				break;
			}
		}
		if (no == 0) {
			cout << "YES" << endl;
		}
		else {
			cout << "NO" << endl;
		}
	}
}

第九题 饿饿 饭饭之暑假大狂欢

题面http://oj.daimayuan.top/course/11/problem/615
逻辑一地鸡毛结果过了,难以理解,首先,数量比当前判断的多的肯定没戏,之后数量小于等于当前的,若两者相同的数等于数量小的个数,如123和12,输出no,还有123,123 也是no,其他情况都是yes

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
int ori[110][110];
vector<int> num[110];
int num1[110];
bool cmp(vector<int> a, vector<int> b) {
	return a[1] > b[1];
}

int main() {
	int t;
	scanf("%d", &t);
	for (int i = 0; i < t; i++) {
		int n;
		scanf("%d", &n);
		num[i].push_back(i);


		int numi = 0;
		for (int j = 0; j < n; j++) {
			int k;
			scanf("%d", &k);
			if (ori[i][k] == 1) {

			}
			else {
				ori[i][k] = 1;
				numi++;
			}
		}
		num[i].push_back(numi);
		num1[i] = numi;
	}
	sort(num, num + t, cmp);
	//cout << 1;
	for (int i = 0; i < t; i++) {
		for (int j = 0; j < t; j++) {
			if (num[j][1] > num1[i]||num[j][0]==i)continue;
			//比较有没有更快或相同的
			//int numj = 0;
			int tong = 0;
			int j1 = num[j][0];
			for (int k = 1; k <= 100; k++) {
				if (ori[j1][k] + ori[i][k]==2) {
					tong++;
				}
				//if (ori[j][k])numj++;
			}
			if (tong == num1[j1]) {
				cout << "NO" << endl;
				goto end1;
			}
			// else {
			// 	cout << "YES" << endl;
			// }
		}
		cout << "YES" << endl;
	end1:;
	}
}

第十题 RSA

题面http://oj.daimayuan.top/course/11/problem/617
本来想用刚学的6x±1来求质数的,结果发现第二个条件基本上绕不过找因数,因为kaa表示两者的因数和要么有出现两次及以上的,要么有因素是平方,所以,只能从头到尾遍历,之后用因素一个大于等于sqrt(n),一个小于等于来压范围

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
//const int maxn = 1e6 + 10;
//int yinzi[maxn];
map<int, int>yinzi;
int main() {
    long long a, b;
    scanf("%lld%lld", &a, &b);
    for (int i = 1; i <= (int)sqrt(a); i++) {
        if (a % i == 0) {
            yinzi[i]++;
            yinzi[a / i]++;
        }
    }
    for (int i = 1; i <= (int)sqrt(b); i++) {
        if (b % i == 0) {
            yinzi[i]++;
            yinzi[b / i]++;
        }
    }
    if (yinzi.size() == 3 && a != b) {
        cout << "full credit" << endl;
        return 0;
    }
    else {
        map<int, int>::iterator it;
        for (it = yinzi.begin(); it != yinzi.end(); it++) {
            if (it->first == 1)continue;
            int itsqrt = (int)sqrt(it->first);
            if (it->second >= 2||itsqrt*itsqrt==it->first) {
                cout << "no credit" << endl;
                return 0;
            }
        }
        cout << "partial credit" << endl;
        return 0;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值