目录
快快变大
给定一个长度为 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位得到abcef
, abc
是abcef
的子串)
一个串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;
}