week16

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

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

#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;
}

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

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

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

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

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

本题了解map函数的基本用法即可解决


#include <iostream>
#include <map>
 
using namespace std;
 
#define int long long
const int mod=1e9+7;
 
map<int,int>mp1;
map<int,int>mp2;
 
void solve()
{
    int op,val,wa;
    cin>>op;
    if(op==1)
    {
        cin>>val>>wa;
        if(mp1.count(val)==0 && mp2.count(wa)==0)
        {
            mp1[val]=wa;
            mp2[wa]=val;
        }
    }
    else if(op==2)
    {
        mp2.erase(mp1.begin()->second);
        mp1.erase(mp1.begin());
    }
    else if(op==3)
    {
        mp1.erase(mp2.begin()->second);
        mp2.erase(mp2.begin());
    }
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int t;
    cin>>t;
    while(t--)
    {
        solve();
 
 
    }
    int ans=0;
    for(auto x:mp1)
        {
            ans+=x.first;
        }
        cout<<ans<<endl;
    return 0;
}

3. 

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

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

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

本题较为简单,对玩家能力值进行排序后,由大往小减,如果该数减去小于他的数大于k,他就能获胜,且能力值比他小的人不可能再获胜,如果小于等于k的话,则两人都有可能获胜。

#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;
}

4.

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

本题掌握dfs的基本使用方法即可

#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 <=n; 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;
}

5.

以不同进制的形式输入 n 个非负整数,求出它们的和并以 m进制的形式输出。

使用大写字母 A ~ Z 依次代表 10 ~ 35, 小写字母 a ~ z 依次代表 36 ~ 61。

本题较为简单,掌握进制转换规律即可

#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;
}

6.

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

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

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

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

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

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

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


#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
using namespace std;
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
typedef long long ll;
typedef pair<ll, ll>PII;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    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;
}

7.

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

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

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

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

想要有利的情况下自己胜出,也就是说选出的数都是自己有的,而且自己在第一个清空前不能有别人比自己先清空。

意思就是自己不能包含别人的全部数:别人不能是自己的子集。比如自己是1 3 5,别人是3 5,那么最好的情况也是别人和我一起清空,这样两边都不能赢,如果自己是1 3 5,别人是3 4,那我只要不删4就行了,这样就是我先赢。

那么我们就记录每个玩家的牌的情况,然后判断我们的牌是否完全包含其它玩家的牌,如果有一个完全包含那我们就不能赢。
 

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int a[105][105], n, x[105], y[105],z[105];
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> x[i];
		for (int j = 1; j <= x[i]; j++)
		{
			cin >> a[i][j];
			if (z[a[i][j]] == 1)
			{
				x[i]--;
				j--;
			}
			z[a[i][j]] = 1;
		}
		sort(a[i] + 1, a[i] + x[i] + 1);//排序
		memset(z, 0, sizeof(z));
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = i + 1; j <= n; j++)//判断两者是否有重叠
		{
			int f = 1;
			if (x[i] == x[j])
			{
				for (int t = 1; t <= x[i]; t++)
				{
					if (a[i][t] != a[j][t])
					{
						f = 0;
						break;
					}
				}
				if (f == 1)
				{

					y[i] = 1;
					y[j] = 1;
				}
			}
			else if (x[j] > x[i])
			{
				int jj = 1, ii = 1;
				if (y[j] == 0)
				{
					while (1)
					{
						if (a[i][ii] == a[j][jj])
							ii++;
						jj++;
						if (ii == x[i] + 1)
						{
							f = 0;
							break;
						}
						if (jj == x[j] + 1)
							break;
					}
					if (f == 0)
						y[j] = 1;
				}
			}
			else
			{
				int jj = 1, ii = 1;
				if (y[i] == 0)
				{
					while (1)
					{
						if (a[i][ii] == a[j][jj])
							jj++;
						ii++;
						if (jj == x[j] + 1)
						{

							f = 0;
							break;
						}
						if (ii == x[i] + 1)

							break;
					}
					if (f == 0)
						y[i] = 1;
				}
			}
		}
	}
	for (int i = 1; i <= n; i++)
	{
		if (y[i] == 1)
			cout << "NO" << '\n';
		else
			cout << "YES" << '\n';
	}
	return 0;
}

8.

RSA算法选择两个不同质数的积作为模数。现在有两个正整数 A,B,如果它们是不同的质数,则判定为 full credit;否则,如果A⋅B不是任意大于1的整数的平方的整数倍,则判定 partial credit;否则判定为no credit

本题了解如何判断一个数为质数的简单方法即可

#include <iostream>
#include <math.h>
using namespace std;
long long x, y, z, ans, a, b, c;
int zhi(long long x)//较为便捷的判断一个数是否为质数
{
	if (x == 1)
		return 0;
	if (x == 2)
		return 1;
	for (int i = 2; i < sqrt(x) + 2; i++)
	{
		if (x % i == 0)
			return 0;
	}
	return 1;
}
int main()
{
	cin >> a >> b;
	if (sqrt(a) == floor(sqrt(a)) || sqrt(b) == floor(sqrt(b)))
	{
		cout << "no credit";
	}
	else
	{
		if (zhi(a) == 1)
		{
			if (zhi(b) == 1)
			{
				if (a == b)
					cout << "no credit";
				else
					cout << "full credit";
			}
			else
			{

				if (b % a == 0)
					cout << "no credit";
				else
					cout << "partial credit";
			}
		}
		else if (zhi(b) == 1)
		{
			if (a % b == 0)
				cout << "no credit";
			else
				cout << "partial credit";
		}
		else
		{
			if (a == b)
				cout << "no credit";
			else
			{
				if (b > a)
				{
					z = b;
					b = a;
					a = z;
				}
				x = 0;
				long long i = 2;
				z = b / 2 + 1;;
				while (i < z)
				{
					if (a % i == 0)
					{
						z = a / i;
						if (b % i == 0 || b % z == 0)
						{
							x = 1;
							cout << "no credit";
						}
					}
					i++;
				}
				if (x == 0)
					cout << "partial credit";
			}
		}
	}
}

9.

给出一串数以及一个数字 C ,要求计算出所有 A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

输入格式

输入共两行。

第一行,两个整数 N, C。

第二行, N 个整数,作为要求处理的那串数。

输出格式

一行,表示该串数中包含的满足 A−B=C 的数对的个数。

本题是一道较为简单的数学分析题,从1到n枚举即可

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;
int a[N], b[N], c, n, x, ans;;
int main()
{
	cin >> n >> c;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	sort(a + 1, a + n + 1);
	int p = 2,j;
	for (int i = 1; i <= n; i++)
	{
		while (1)
		{
			if (p > n)
				break;
			if (a[p] - a[i] == c)
			{
				j = i;
				int sum = 0;
				while (a[p] - a[j] == c)
				{
					ans++;
					j++;
					sum++;
				}
				while (a[p] == a[p + 1])
				{
					p++;
					ans += sum;
				}
				p++;
				break;
			}
			if (a[p] - a[i] > c)
			{
				break;
			}
			p++;
		}
		if (p == n + 1)
			break;
	}
	cout << ans;
	return 0;
}

10.

由于本题的数据范围很大,所以需要用到巧妙的高精度算法

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int main() {
	int i, j, k, n, m; 
	long long f1, f2, f3; 
	cin >> f1; 
	n = 0; 
	for (f2 = 1; f2 < f1; f2 = f2 * 10 + 1)
		n++; 
	while (1) 
	{
		n++; 
	if (f2 % f1 == 0) 
	{
		cout << f2 / f1; break;
	}
	else
	{ 
		cout << f2 / f1; f2 %= f1; f2 = f2 * 10 + 1; //巧妙的高精度算法
	}
	}
	cout << " " << n << endl;
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值