快快变大、删删、循环子串

目录

快快变大

删删

#563. 子串分值和

#561. 饿饿 饭饭2

#605. 蒟蒻

锦标赛

可重排列

进制转换


快快变大

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

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

输入格式

第一行一个数字 nn。

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

输出格式

一个数,表示答案。

样例输入

3
1 2 3

样例输出

26

数据规模

所有数据保证 1≤n≤300,1≤ai≤1061≤n≤300,1≤ai≤106。

 类似石子合并(然而我忘了具体dp思路)

用一个二维数组预处理下各个区间的乘积和,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]));

第一层循环是控制数组的长度,第二层循环是控制起点但i只能到 i+len-1<=n,(第三层循环控制分界点

位置)

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


typedef long long ll;
const int N = 1010, MOD = 1000003;
ll 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;
}

删删

 附加文件 统计

给定一个字符串,你可以删除多个(可以是 00) 相同 的字符,这样操作之后,你能否得到一个回文串?如果能,求最小化删除的个数。

输入格式

多组数据。

每一组数据包含两行,分别为字符串的长度 NN,以及一个仅由小写字母组成的字符串 SS。

输出格式

对于每一组数据,输出一行。

如果不可能得到一个回文串,输出 −1−1。反之则输出最小操作次数。

样例输入

4
8
bilibili
3
qwq
9
daimayuan
7
xcpcxpc

样例输出

1
0
-1
2

解释:

在第一个例子中,删除开头的 b 得到 ilibili

第二个例子中,qwq 本身已回文,不需要操作。

第三个例子中,可以看到 daimayuan 不能靠仅删除一种字符得到一个回文串。

数据规模

  • 1≤N≤1051≤N≤105, 但保证 ∑N≤2×105

 运用双指针对26个字符的每一个进行枚举,看删除后能否变为回文串

#include<iostream>
#include<cstring>
#define endl '\n'
using namespace std;
int n,t,st,ed;
string s;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>t>>s;
		int res = 0x3f3f3f3f;
		for(int j=97;j<=122;j++)
		{
			int ans=0,flag =1;
			st = 0,ed = t-1;
			while(st<ed)
			{
				if(s[st]!=s[ed])
				{
					if(s[st]==j)st++,ans++;
					else if(s[ed]==j)ed--,ans++;
					else 
					{
						flag = 0;
						break;
					}
				}
				else if(s[st]==s[ed])
				{
					 st++,ed--;
				}
			}
			if(flag)
			res = min(res,ans);
		}
		if(res == 0x3f3f3f3f)cout<<-1<<'\n';
		else cout<<res<<'\n';
	}
	return 0;
}

#563. 子串分值和

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

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

输入格式

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

输出格式

输出一个整数表示答案。

样例输入

ababc

样例输出

28

数据规模

所有数据保证字符串长度 len≤1000000len≤1000000,字符串下标从 00 到 len−1len−1。

 1.一个长度为len的字符串一共有ans = (len+1)*len/2个子串

2.找到子串出现的不同字符个数不容易,我们可以找子串没有出现的字符的个数

3.通过枚举a-z获得,对于char i 属于(a--z),假设每个子串都含有字母i,找到每个字母i出现的起始位置st和结束位置ed,中间长度为(ed-st)的字符串是不含有字母i的,从ans里面减去(ed-st)长度的字符串含有的子串个数即可。

4.特别判断每个字符第一次出现的位置和最后一次出现的位置即可

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
ll ans,res,len,flag;//用flag标记该字符串是否含有字母i
int main()
{
	string sh;
	cin>>sh;
	len = sh.size();
	for(char i='a';i<='z';i++)
	{
		ans = len*(len+1)/2,flag=0;
		int st=-1,ed=-1;
		for(int j=0;j<len;j++)
		{
			if(sh[j]==i)
			{
				st = ed;
				ed = j;
				if(st==-1)//起始位置
				ans-=ed*(ed+1)/2;
				else 
				ans-=(ed-st)*(ed-st-1)/2;
				flag = 1;
//				cout<<"i  "<<"st  "<<"ed   "<<"ans  "<<'\n';
//				cout<<i<<"  "<<st<<"  "<<ed<<"  "<<ans<<'\n';
			}
		}
		if(flag)
		{
			ans-=(len-ed)*(len-ed-1)/2;//结束位置
			res+=ans;
		}
		
	}
	cout<<res;
	return 0;
	
}

#561. 饿饿 饭饭2

接着《饿饿 饭饭》 的故事,在两天后,食堂的工作人员回来了,整个食堂又回到了原来井井有条的状态。

两个月后,由于天气越来越热,大家的胃口越来越小了,作为食堂管理员的CC非常担心孩子们的身体健康,所以他决定开展一个活动来调动孩子们吃饭的积极性,顺便考验一下孩子们的数学水平。活动内容如下:

先让每一个孩子都抽一个球,每一个球上有一个数字, 然后给这个孩子nn个数字,每一个孩子都有无数次操作机会,每一次都会选中一个数将它乘上22,或者乘上33,请问这个孩子可以通过上面的操作将这nn个数都变成相同的吗?

如果回答正确,这个回答正确的孩子就可以得到一份免费的午餐,但是这对于孩子们来说是在是太困难了,但是他们都想吃到免费的午餐,所以他们都想请你告诉他们正确的答案,让他们都迟到免费的午餐。

输入格式

第11行给定一个数TT,表示有TT个小孩子请你告诉他正确的答案。

第22到T+1T+1行,第11个数是每个孩子抽到的数字nn,第22到n+1n+1个数是对应的nn个数字。

输出格式

如果可以变成相同的,输出YES。如果不能变成相同的,输出NO

数据规模

1≤T≤100,1≤n≤2×105,1≤ai≤1091≤T≤100,1≤n≤2×105,1≤ai≤109

数据保证∑Ti=1n≤2×105∑i=1Tn≤2×105

样例输入

2
4 75 150 75 50
3 100 150 250

样例输出

YES
NO

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

2.不知道除去多个2和除去多个3的先后顺序,需要通过dfs进行回溯搜索(这个倒是忘考虑了,参考了大佬的博客才发现QAQ)。代码源:561、饿饿 饭饭2 - 掘金 (juejin.cn)


#include<iostream>
#include<vector>
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()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    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;
}

#605. 蒟蒻

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

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

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

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

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

输入格式

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

第 22 行至第 (n+1)(n+1) 行,每行 一个或三个 整数,分别表示 opop,ww,tt。

ww 和 tt 当且仅当 op=1op=1 时存在。

输出格式

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

样例输入

6
1 1 1
1 2 5
2
1 3 3
3
1 5 2

样例输出

7

数据规模

所有数据保证 1≤n≤1051≤n≤105,1≤w,t≤1061≤w,t≤106,且保证输入合法

熟悉map的用法,默认按照键从小到大排序,map的访问:auto x : map 。(用vector再慢慢排序会超时) 

#include <bits/stdc++.h>
 
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());
    }
}
 
signed 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;
}

锦标赛

题目描述

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

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

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

输入格式

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

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

输出格式

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

样例输入1

5 3
1 5 9 6 3

样例输出1

5

样例输入输出2

见下发文件。

数据规模

共10组数据。

测试点11满足n≤5n≤5。

测试点22满足n≤10n≤10。

测试点3,4,53,4,5满足n≤1000n≤1000。

对于100%100%的数据,满足n≤105,1≤ai,K≤109n≤105,1≤ai,K≤109。

 找多少种可能不太容易,反过来找出必败的人

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 7;
const int mod = 1e9+7;
int a[N];
int n,k,ans=1;
signed main(){

cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
for(int i=n;i>=2;i--)
{
	if(a[i]-a[i-1]<=k)ans++;
	else break;
}
cout<<ans<<endl;
return 0;	
}

可重排列

请按字典序从小到大的顺序输出所有序列,满足序列中有 p1p1 个 11, p2p2 个 22, ……, pnpn 个 nn。

输入格式

第一行一个整数 nn。

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

输出格式

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

样例输入

3
1 2 2

样例输出

1 2 2 3 3
1 2 3 2 3
1 2 3 3 2
1 3 2 2 3
1 3 2 3 2
1 3 3 2 2
2 1 2 3 3
2 1 3 2 3
2 1 3 3 2
2 2 1 3 3
2 2 3 1 3
2 2 3 3 1
2 3 1 2 3
2 3 1 3 2
2 3 2 1 3
2 3 2 3 1
2 3 3 1 2
2 3 3 2 1
3 1 2 2 3
3 1 2 3 2
3 1 3 2 2
3 2 1 2 3
3 2 1 3 2
3 2 2 1 3
3 2 2 3 1
3 2 3 1 2
3 2 3 2 1
3 3 1 2 2
3 3 2 1 2
3 3 2 2 1

数据规模

对于 100%100% 的数据,保证 1≤n≤9,1≤pi≤91≤n≤9,1≤pi≤9,保证满足条件的序列个数不超过 105105 个。

next_permutation函数直接用就可以了。注意输入输出用scanf、printf防止卡时间 

(219条消息) C++中全排列函数next_permutation 用法_Marcus-Bao的博客-CSDN博客

#include<bits/stdc++.h>
using namespace std;
vector <int > v;
int n;
signed main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int num;
		scanf("%d",&num);
		for(int j=1;j<=num;j++)v.push_back(i);
	}
 do {
		for(int i=0;i<v.size();i++)
		{
			if(i==0)printf("%d",v[i]);
			else
			printf(" %d",v[i]);
		}
		printf("\n");
    } while (next_permutation(v.begin(),v.end()));
	return 0;
}

进制转换

 

题面

让我看看是谁不会进制转换,哦原来是我


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

使用大写字母 A ~ Z 依次代表 1010 ~ 3535, 小写字母 a ~ z 依次代表 3636 ~ 6161。

输入格式

第一行输入两个整数 1≤n≤101≤n≤10 , 2≤m≤622≤m≤62 。

接下来 nn 行,每行输入一个整数 2≤t≤622≤t≤62, 一个 tt 进制数 0≤x≤1090≤x≤109。

输出格式

一个 mm 进制数,为最终的结果

输入样例1

2 2
2 1
6 10

输出样例1

111

输入样例2

1 10
52 aA0

输出样例2

97864

输入样例3

2 52
36 AMD
52 YES

输出样例3

dJD

进制转换用栈进行输出即可 

#include<iostream>
#include<cstring>
#include<stack>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,t;
long long ans;
string x;
stack <char> s;
void change(int res)
{
 	 if(res>=10&&res<=35)s.push(res-10+'A');
	 else if(res>=36&&res<=61)s.push(res-36+'a');
	 else s.push(res+'0');
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>t>>x;
		for(int j=x.size()-1;j>=0;j--)//字符串最后一个字符是最小的一位数
		{
			int tm;
			if(x[j]>='A'&&x[j]<='Z')			
				tm=x[j]-'A'+10;			
			else if(x[j]>='a'&&x[j]<='z')
				tm=x[j]-'a'+36;			
			else tm = x[j]-'0';
			ans=ans+tm*pow(t,x.size()-1-j);
		}
	}
	while(ans)
	{
		int res = ans%m;
		change(res);
		ans/=m;
	}
	while(s.size())
	{
		cout<<s.top();
		s.pop();
	}
	return 0;
}

#552. 循环子串

题目描述

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

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

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

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

输入格式

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

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

输出格式

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

数据范围

对于所有数据 有 1≤t≤1001≤t≤100, 1≤n≤1031≤n≤103, ∑n≤103∑n≤103。

样例输入

2
4
ccca
11
eeaafbddfaa

样例输出

YES
NO

提示 选中可以查看

1. 本道题目只需要语法知识就可以解决。

2. 任意子串是什么意思呢?

1.字符串的位移直接不好实现,不如将位移后可以得到的字符串与原字符串拼接在一起

2.题目数据较小,通过枚举每个字符串的起始位置和长度即可;

3.可以借助find(),substr()函数实现

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int t, n, flag;
string sh;
int main()
{
	ios::sync_with_stdio(false);//取消流同步加快读取速度
	cin.tie(0), cout.tie(0);
	cin >> t;
	while (t--)
	{
		flag = 1;
		cin >> n;
		cin >> sh;
		sh += sh;
		for (int i = 0; i < n; i++)//起始位置
		{
			for (int j = 2; i + j < n; j++)//长度
			{
				string ch = sh.substr(i, j);
				reverse(ch.begin(), ch.end());
				if(sh.find(ch)==sh.npos)flag=0;
			}
			if (!flag)break;
		}
		if (flag)puts("YES");
		else puts("NO");
	}
	return 0;
}

饿饿 饭饭之暑假大狂欢

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

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

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

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

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

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

输入格式

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

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

输出格式

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

数据范围

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

样例输入

3
1 1
3 2 4 1
2 10 11

样例输出

YES
NO
YES

自己在第一个清空前不能有他人比自己先清空。自己不能包括他人的全部数,他人不能是自己的子集。即:只要他人有自己没有的数,那么自己便可以赢。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<unordered_map>
#include<vector>
const int N = 105;
int v[N][N];
int t, n, cnt=1;
using namespace std;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> t;
	for (int i = 1; i <= t; i++)
	{
		cin >> n;
		for (int j = 1; j <= n; j++)
		{
			int num; cin >> num;
			v[i][num] = 1;//第i个人存在该数num
		}
	}
	for (int i = 1; i <= t; i++)
	{
		int res=1;
		for (int j = 1; j <= t; j++)
		{
			int flag = 0;
			if (i == j)continue;
			for (int k = 1; k <= 100; k++)
			{
				if (!v[i][k] && v[j][k])//第j个人有数k而第i个人没有,第i个人便可以先清空
				{
					flag = 1;
					break;
				}
			}
			if (!flag)
			{
				res = 0;
				break;
			}
		}
		if (res)puts("YES");
		else puts("NO");
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值