week15

1.

你有一个序列,现在你要支持几种操作:

  • insert x y,在从前往后的第x个元素后面插入y这个数。如果x=0,那么就在开头插入。

  • delete x,删除从前往后的第x个元素。

  • query k,询问从前往后数第k个元素是多少。

输入格式

第一行一个整数m,表示操作个数。

接下来m行,每行一个上面所述的操作。

输出格式

输出若干行,对于每个查询操作,输出答案。

本题知道vector函数的基本用法即可

#include<iostream>
#include<vector>
#include<string>
using namespace std;
vector<int> v;
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int m;
	cin >> m;

	while (m--) {
		string str;
		cin >> str;
		if (str == "insert") {
			int a, b;
			cin >> a >> b;
			auto ite = v.begin();
			while (a--)ite++;
			v.insert(ite, b);
		}
		else if (str == "query") {
			int a;
			cin >> a;
			auto ite = v.begin();
			while (--a)ite++;
			cout << *ite << '\n';
		}
		else if (str == "delete") {
			int a;
			cin >> a;
			auto ite = v.begin();
			while (--a)ite++;
			v.erase(ite);
		}
	}
	return 0;
}

2. 

给定一个长度为 n 的数组 a1,a2,…,an,接下来进行 n−1次操作。每次选择一个下标 x 将 ax�和 ax+1 合并成 ax×ax+1mod1000003 ,并且你会获得 (ax−ax+1)2 的分数。

所以每次操作后,数组的长度将会减 11,当最后只剩下一个元素时停止操作。输出最终能获得的最大分数。

输入格式

第一行一个数字 n。

接下来一行 n 个整数 a1,a2,…,an。

输出格式

一个数,表示答案。

本题我们可以先用一个二维数组预处理下各个区间的乘积和,s[i] [j]的意思是ai到aj的乘积。用一个二维动规数组f来做区间dp,dp[i] [j]意思是合并i到j可以得到的最大分数。然后我们从长度2开始枚举区间长度,来获得每个区间所能得到的最大分数。最后答案就是dp[1] [n]。

状态转移方程为

f[i][j] = max(f[i][j], f[i][k] + f[k + 1][j] + (s[i][k]-s[k+1][j])* (s[i][k] - s[k + 1][j]));

下面附上代码

#include<iostream>
using namespace std;
const int N = 1010, MOD = 1000003;
long long f[N][N], s[N][N],v[N];
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> v[i];
    }
    for (int i = 1; i <= n; i++)
    {
        s[i][i] = 1;
        s[i][i-1] = 1;
        for (int j = i; j <= n; j++)
        {
            s[i][j] = (v[j] * s[i][j - 1]) % 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++)
            {
                f[i][j] = max(f[i][j], f[i][k] + f[k + 1][j] + (s[i][k]-s[k+1][j])* (s[i][k] - s[k + 1][j]));
            }
        }
    }
    cout << f[1][n] << endl;
    return 0;

3.

对于本题,如果两个数通过乘上多个2和3可以达到相等,那么反过来,这两个数通过除去多个2和3也可以达到相等。而且这个相除后得到的数应该是这两个数之间的最大公约数。

那么这题就很好写了,我们只要求出来n个数之间的最大公约数,然后把这n个数除去多个2或3(整除),判断这些数能不能变成最大公约数,要是不行,说明这n个数不能达到完全相同,输出no。如果没有,那就输出yes。

#include<iostream>
using namespace std;
int gcd(int a, int b)
{
    if (a % b == 0)return b;
    return gcd(b, a % b);
}
bool dfs(int num,int k)
{
    if (num < k)return false;
    bool a = false, b = false;
    if (num % 2 == 0)a = dfs(num / 2, k);
    if (num % 3 == 0)b = dfs(num / 3, k);
    return a || b || num == k;
}
int main()
{

    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        vector<int>v(n);
        for (int i = 0; i < n; i++)cin >> v[i];
        int res = v[0];
        for (int i = 1; i < n; i++)
        {
            res = gcd(v[i], res);
        }
        bool flag = true;
        for (int i = 0; i < n; i++)
        {
            
            if (v[i]!=res&&!dfs(v[i], res))
            {
                cout << "NO" << endl;
                flag = false;
                break;
            }
        }
        if (flag)cout << "YES" << endl;
    }
    return 0;
}

4.

对于一个字符串 S ,我们定义 f(S) 为 S 中出现的不同的字符个数。 例如 f(aba)=2,f(abc)=3,f(aaa)=1。

现在给定一个字符串 S (假设长度为 len),请你计算 ∑i=0len−1∑j=ilen−1f(S[i:j]) 。

输入格式

输入一行包含一个由小写字母组成的字符串 S 。

输出格式

输出一个整数表示答案。

对于本题,我们可以发现,对于i=1以及i=2两种情况,当i=2的字串第一次出现s[1]时,从此往后,i=2的字串与i=1的字串的f(s)相同,发现了这个规律后,本题就非常简单了。

#include <iostream>
#include <string.h>
#include <cstring>
using namespace std;
const int N = 1e6 + 5;
string s;
long long a[28], b[N], c, x, y, z, sum;
long long ans;
int main()
{
	cin >> s;
	c = s.length();
	for (int i = 0; i < c; i++)
	{
		if (a[s[i] - 96] == 0)
		{
			sum++;
			a[s[i] - 96] = 1;
		}
		ans += sum;
	}
	b[0] = ans;
	for (int i = 1; i < c; i++)
	{
		b[i] = b[i - 1] - 1;
		for (int j = i; j < c; j++)
		{
			if (s[j] != s[i-1])
				b[i]--;
			else
				break;
		}
		ans += b[i];
	}
	cout << ans;
	return 0;
}

5.

便利蜂的货架上摆了一排蒟蒻果冻,搞得鶸尛鱻眼花缭乱......

对于每个果冻,都有一个价格 w 和口感 t。鶸尛鱻有一个购物篮子,在挑选蒟蒻果冻的时候,他有以下几种操作:

  • 操作 11:把一个价格为 w,口感为 t 的果冻放入篮子。
  • 操作 22:拿出篮子中 最为廉价 的果冻。
  • 操作 33:拿出篮子中 口感最差 的果冻。(t 越小,口感越差)

鶸尛鱻不喜欢重复,当操作 11 的 价格或口感 与篮中已有果冻重复时,他会立刻将其放回货架。

经过 n 次操作后,鶸尛鱻确定了要购买的若干果冻,请你帮他求出篮子里果冻的总价格。

输入格式

第 11 行一个正整数 n,代表操作次数。

第 22 行至第 (n+1) 行,每行 一个或三个 整数,分别表示 o,w,t。

w 和 t 当且仅当 op=1 时存在。

输出格式

输出一个整数,表示篮子里果冻的总价格。

本题掌握map的基本用法即可

#include<iostream>
#include<map>
using namespace std;



int main() {

    int n,ans=0;
    cin >> n;
    map<int, int>p, t;
    while (n--)
    {
        int st;
        cin >> st;
        if (st == 1)
        {
            int a, b;
            cin >> a >> b;
            if (p.count(a) == 0 && t.count(b) == 0)
            {
                p[a] = b;
                t[b] = a;
            }
        }
        else if (st == 2)
        {
            t.erase(p.begin()->second);
            p.erase(p.begin());
        }
        else if (st == 3)
        {
            p.erase(t.begin()->second);
            t.erase(t.begin());
        }
    }
    ll sum = 0;
    for (auto i : p)sum += i.first;
    cout << sum << endl;
    return 0;
}

6.

有n个玩家参加比赛,他们分别有能力值a1,a2,…,an。

需要进行n−1轮比赛,每一轮在剩下的玩家里任选两个玩家i,j。如果|ai−aj|>K,那么其中能力值高的玩家会获胜,能力值低的玩家会被淘汰。如果|ai−aj|≤K,那么两个玩家都有可能获胜,另一个玩家被淘汰。

n−1轮比赛之后,只剩下一个玩家。问有多少个玩家可能是最后获胜的玩家。

输入格式

第一行,两个整数n,K,表示玩家的总人数,和获胜条件中的参数。

接下来一行n个整数a1,a2,…,an,表示玩家的能力值。

输出格式

一个整数,表示最后可能获胜的玩家个数。

本题我们从能力值由大到小依次遍历即可,如果排序后第i个玩家的能力值减去第i-1个玩家的大于k,那么对于这i-1个玩家来说是不可能获胜的。

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
int a[N], n, k, ans=1;
int main()
{
	cin >> n >> k;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	sort(a+1, a + n + 1);
	for (int i = n; i >= 2; i--)
	{
		if (a[i] - a[i - 1] <=k)
			ans++;
		else
			break;
}
	cout << ans;
}

7.

请按字典序从小到大的顺序输出所有序列,满足序列中有 p1 个 1, p2个 2, ……, pn 个 n。

输入格式

第一行一个整数 n。

第二行 n个整数 p1,p2,…,pn。

输出格式

按字典序从小到大的顺序一行一行输出所有满足条件的序列,每行一个序列,相邻两个数字需要用空格隔开。

对于本题,使用递归即可

#include <iostream>
using namespace std;
int n,a[10],c,p[100],sum;
void dfs(int x)
{
	if (x == sum + 1)
	{
		for (int i = 1; i <= c; i++)
			cout << p[i] << " ";
		cout << '\n';
	}
	else
	{
		for (int i = 1; i <=; i++)
		{
			if (a[i] != 0)
			{
				a[i]--;
				c++;
				p[c] = i;
				dfs(x + 1);
				c--;
				a[i]++;
			}
		}
	}
}
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		sum += a[i];
	}
	dfs(1);
	return 0;
}

8.

本题了解各进制之间的转换即可,注意开longlong

#include <iostream>
#include <string.h>
using namespace std;
long long n, m, x,a[10000],sum;
string s;
int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		long long p = 1;
		cin >> x >> s;
		for (int i = s.length()-1; i >=0; i--)
		{
			if (s[i] >= 'A' && s[i] <= 'Z')
				sum += p * (s[i] - 55);
			else if (s[i] >= 'a' && s[i] <= 'z')
				sum += p * (s[i] - 61);
			else
				sum += p * (s[i] - 48);
			p *= x;
		}
	}
	int q = 1;
	a[q] = sum;
	while (1)
	{
		a[q + 1] = a[q] / m;
		a[q] = a[q] % m;
		q++;
		if (a[q] < m)
		{

			break;

		}
	}
	for (int i = q; i >= 1; i--)
	{
		if (a[i] >= 10 && a[i] <= 35)
		{
			char f = a[i] + 55;
			cout << f;
		}
		else if (a[i] >= 36 && a[i] <= 61)
		{
			char f = a[i] + 61;
			cout << f;
		}
		else
			cout << a[i];
	}
	return 0;
}

9.

题目描述

一个字符串S是另一字符串T的循环子串当且仅当存在k, T所有字符循环右移k位后得到的新串T′,满足S是T′的子串。

例如: abc 是 cefab的循环子串。 (cefab循环右移22位得到abcefabcabcef的子串)

一个串P是完全循环串当且仅当对于它的任一子串H, 都有Hreverse是P的循环子串 (Hreverse 为 H的倒转, 如abc reverse后 为cba)。

给一个长度为n的字符串, 判断它是不是完全循环串。

输入格式

第一行一个正整数t, 表示测试数据组数。

对于每一组数据,第一行一个正整数n, 表示字符串的长度。接下来一行一个长度为n的字符串. 仅包含小写字母。

输出格式

对于每组测试数据,如果这个串是完全循环串, 输出YES,否则输出NO。每组测试数据之间输出换行。

数据范围

对于所有数据 有 1≤t≤100, 1≤n≤1e3, ∑n≤1e3。

本题的意思为字符串s的所有子串翻过来之后(abc变cba)能在s里找到一样的字符串,这个s可以是向右移动k次之后的样子(向右移动k次相当于把前面k个字符移动到末尾,比如abcde移动2次,那就变成cdeab)。

那么我们只要枚举所有可能的子串,然后在旋转后的字符串s里找看是不是都能找到即可,如果都能找到那就输出yes,一个找不到都要输出no。可是每次都要移动字符串s太麻烦了,所以我们要对字符串做点改变。

就像我们前面说的,移动k次是把前k个字符删除移动到末尾,那么最多移动len(字符串长度)次,字符串就会变回原样,那我们直接把一个相同的字符串s接到s后面即可,这样就可以在这个字符串里找到所有可能移动过后的字符串s,我们在这里面找子串即可。

#include<iostream>
#include<string.h>
using namespace std;

int main()
{

    int t;
    cin >> t;
    while (t--)
    {
        int n;
        string s;
        cin >> n >> s;
        bool flag = true;
        string str = s + s;
        for (int len = 2; len <= n; len++)
        {
            for (int i = 0; i + len <= n; i++)
            {
                string res = s.substr(i, len);
                reverse(res.begin(), res.end());
                if (str.find(res) == str.npos)
                {
                    cout << "NO" << endl;
                    flag = false;
                    break;
                }
            }
            if (!flag)break;
        }
        if (flag)cout << "YES" << endl;
    }
    return 0;
}

10.

故事接着《饿饿 饭饭 2》,又过了几个月,暑假来啦!!!

这天,cc和他的小伙伴们决定一起去游乐园玩,他们一天将游乐园的所有设施玩了个遍,甚至大摆锤,过山车他们还去了很多次,愉快的时间总是很短暂的,很快时间就来到了晚上,但是你以为一天的娱乐时光就这样结束了吗,那你就猜错啦。

晚上,游乐园晚上的party就开始啦,其中有一个游戏环节,赢的人可以得到免费的西瓜,饿到不行的cc和他的小伙伴非常希望得到这个西瓜。

包括cc和他的小伙伴,有t个玩家参与了这个游戏,每个玩家都有一张带有数字的卡片。第i�张卡片上有ni个数字,分别是m1,m2,...mn。

游戏过程中,主持人从袋子里一个一个地取出编号的球。 他用洪亮而清晰的声音大声念出球的编号,然后把球收起来。 如果玩家的卡片上有对应的数字,就可以将它划掉。 最先从他的卡片上划掉所有数字的人获胜。 如果多人同时从他们的卡片上划掉所有数字,那么这些人都不能赢得比赛。 在游戏开始时,袋子里有 100 个球,编号从 1 到 100,所有球的编号都是不同的。

cc偷偷知道了每个玩家的数字。 想请你确定每个玩家是否可以在最有利于他的情况下赢得比赛。

输入格式

第一行给出一个数t,代表t个玩家。

接下来第二行到t+1行,每行第一个数为ni,代表这个人手中有n个卡片,接下来给出序列a1...an表示这个人所拥有的卡片的数字。

输出格式

输出t行,每一行给出第i个人在最有利的情况下是否能赢得比赛,可以输出YES, 不可以输出NO

数据范围

1≤t≤100,1≤n≤100,1≤mi≤100

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值