div2 每日一题
305 删删
-
暴力
-
#include<bits/stdc++.h> using namespace std; int t; int main() { cin.tie(0); cout.tie(0); cin>>t; while(t--) { int n,ans=1e9,sum=0; string s; cin>>n>>s; for(char i='a';i<='z';i++) { bool flag=true; int l=0,r=n-1,sum=0; while(l<r) { if(s[l]==s[r]) l++,r--; else { if(s[l]==i) l++,sum++; else if(s[r]==i) r--,sum++; else { flag=false; break; } } } if(flag) ans=min(ans,sum); } if(ans==1e9) cout<<"-1"<<endl; else cout<<ans<<endl; } return 0; }
306 快快变大(区间dp)
-
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+cost)
cost指代把dp[i][k] 和 dp[k+1][j] 的两个区间合并起来的花费
-
注意i k合并后的数值要预处理不然可能会超时
-
#include <bits/stdc++.h> #define ll long long using namespace std; const int mx=1e3+5; const int INF=0x3f3f3f3f; ll n,t=0; ll f[301][301],aa[301][301]; int main() { cin.tie(0); cout.tie(0); cin>>n; ll a[n+1]; for(int i=1;i<=n;i++) { scanf("%ld",&a[i]); f[i][i]=0; aa[i][i-1]=1; } for(int i=2;i<=n;i++) { f[i-1][i]=pow(a[i-1]-a[i],2); } for(int i=1;i<=n;i++) { for(int j=i;j<=n;j++) { aa[i][j]=aa[i][j-1]*a[j]%1000003; } } for(int l=2;l<=n;l++) { for(int i=1;i+l-1<=n;i++) { int j=i+l-1; for(int k=i;k<j;k++) { ll tp3=pow(aa[i][k]-aa[k+1][j],2); f[i][j]=max(f[i][k]+f[k+1][j]+tp3,f[i][j]); } } } printf("%ld",f[1][n]); }
307饿饿 饭饭2
题目描述
接着《饿饿 饭饭》 的故事,在两天后,食堂的工作人员回来了,整个食堂又回到了原来井井有条的状态。两个月后,由于天气越来越热,大家的胃口越来越小了,作为食堂管理员的CC非常担心孩子们的身体健康,所以他决定开展一个活动来调动孩子们吃饭的积极性,顺便考验一下孩子们的数学水平。活动内容如下:
先让每一个孩子都抽一个球,每一个球上有一个数字, 然后给这个孩子n个数字,每一个孩子都有无数次操作机会,每一次都会选中一个数将它乘上2,或者乘上3,请问这个孩子可以通过上面的操作将这n个数都变成相同的吗?
如果回答正确,这个回答正确的孩子就可以得到一份免费的午餐,但是这对于孩子们来说是在是太困难了,但是他们都想吃到免费的午餐,所以他们都想请你告诉他们正确的答案,让他们都迟到免费的午餐。
输入格式
第1行给定一个数T,表示有T个小孩子请你告诉他正确的答案。第2到T+1行,第1个数是每个孩子抽到的数字n,第2到n+1个数是对应的n个数字。
输出格式
如果可以变成相同的,输出YES。如果不能变成相同的,输出NO。数据规模
1 ≤ T ≤ 100 , 1 ≤ n ≤ 2 × 1 0 5 , 1 ≤ a i ≤ 1 0 9 1≤T≤100,1≤n≤2×10^5,1≤a_i≤10^91≤T≤100,1≤n≤2×10
5
,1≤a
i
≤10
9
数据保证∑ i = 1 T n ≤ 2 × 1 0 5 ∑^T_{i=1}n≤2×10^5∑
i=1
T
n≤2×10
5
样例输入
2
4 75 150 75 50
3 100 150 250
1
2
3
样例输出
YES
NO
1
2
思路
先找到这n个数的最大公因数,接着除以最大公因数,接下来判断每个数是否能被2和3整除到1,但凡有一个未除以到1,则答案为NO#include <bits/stdc++.h> using namespace std; const int Max = 2e5+5; int t,n; long long a[Max]; int main(){ cin >> t; for(int i = 1; i <= t; i++){ cin >> n; memset(a,0,sizeof(a)); long long gcd; for(int j = 1; j <= n; j++) cin >> a[j]; gcd = a[1]; //cout << a[1] << endl; for(int j = 2; j <= n; j++){ gcd=__gcd(gcd,a[j]); //cout << gcd << endl; } //cout << gcd << endl; for(int j = 1; j <= n; j++){ a[j]/=gcd; while(a[j]%3==0 || a[j]%2==0){ if(a[j]%3==0) a[j]/=3; if(a[j]%2==0) a[j]/=2; } } int flag=0; for(int j = 1; j <= n; j++){ if(a[j]!=1) { flag=1; break; } } if(flag==0) cout << "YES" << endl; else cout << "NO" << endl; } }
401子串分值和
思路
对于样题:
对于每个子串来说,字母第一次出现且被包含,包含其的子串的F必然会算上该字母,即+1,每个包含该字母的子串F值都要算上该字母,故所有字母第一次出现包含其的子串数和即为答案
而我们之前做到过一道类似的,包含字母x的字串总个数与该字母左右个数有关,即l+r+l*r+1
此题我们用map来记录上一个字母出现的位置,注意s从0开始,但是我们记录的时候要加1
#include <bits/stdc++.h>
using namespace std;
string s;
map<char, int> q;
int main(){
cin >> s;
long long ans = 0;
int len = s.length();
for(int i = 1; i <= len; i++){
//cout << 1+len-i+i-q[s[i-1]]-1+(i-q[s[i-1]]-1)*(len-i) << endl;
ans += 1+len-i+i-q[s[i-1]]-1+(i-q[s[i-1]]-1)*(len-i);
q[s[i-1]]=i;
//cout << i-1 << " ";
//cout << ans << " ";
// cout << s[i-1] << " ";
}
cout << ans << endl;
}
402蒟蒻
思路
直接map,可以去重的同时选取最小的
#include <bits/stdc++.h>
using namespace std;
map<int, int> q1;
map<int, int> q2;
int n;
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
int op,w,t;
cin >> op;
if(op==1){
cin >> w >> t;
if(q1.count(w)==0 && q2.count(t)==0){
q1[w]=t;
q2[t]=w;
}
}
else if(op==2){
q2.erase(q1.begin()->second);
q1.erase(q1.begin());
}
else if(op==3){
q1.erase(q2.begin()->second);
q2.erase(q2.begin());
}
}
int ans = 0;
for(auto x:q1){
ans+=x.first;
}
cout << ans << endl;
}
403锦标赛
思路
升序排序,找最大的t使得∣ a t − a t − 1 ∣ > K |a_t−a_{t-1}|>K∣a t−at−1∣>K,则在t之前的所有小于a t a_ta 的数最终都会被淘汰掉,因为总可以找到一个数使得∣ a x − a ∣ > K |a_x-a|>K∣a
x −a∣>K;
找到该数t之后,t~n即最终可能留下的数,即n-t+1个数
#include <bits/stdc++.h>
using namespace std;
const int Max = 1e5+5;
int n;
long long k;
long long a[Max];
int main(){
cin >> n >> k;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a+1,a+n+1);
int t=1;
for(int i = 2; i <= n; i++){
if(abs(a[i]-a[i-1])>k) t=i;
}
//cout <<t << endl;
cout << n-t+1;
}
404可重排列
思路
dfs深搜
#include <bits/stdc++.h>
using namespace std;
const int Max = 1e5+5;
int vis[10];
int a[Max];
int n;
int num=0;
void print(){
for(int i = 1; i <= num; i++){
printf("%d ",a[i]);
}
//cout << endl;
printf("\n");
}
void dfs(int s){
if(s == num+1){
print();
return;
}
for(int i = 1; i <= 9; i++){
if(vis[i]!=0){
a[s]=i;
vis[i]--;
dfs(s+1);
vis[i]++;
}
}
}
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
//cin >> vis[i];
scanf("%d", &vis[i]);
//cout << i << ":" << vis[i] << endl;
num+=vis[i];
}
//cout << num << endl;
dfs(1);
}
405进制转换
思路
先转换为十进制,后做运算,再辗转相除逆置转换为m进制输出
#include <bits/stdc++.h>
using namespace std;
int n,m;
char x[200];
int d[200];
void ini(){
int j = 0;
for(char i='0'; i<='9'; i++,j++){
x[j]=i;
d[i]=j;
}
int k = 36, s= 10;
for(char i = 'a', j = 'A'; i<='z'; i++,j++){
x[k]=i;
x[s]=j;
d[j]=s;
d[i]=k;
k++; s++;
}
}
int main(){
cin >> n >> m;
ini();
long long ans=0;
for(int i = 1; i <= n; i++){
int t;
string s;
cin >> t >> s;
int len = s.length();
//cout << s << endl;
for(int j = len-1; j>=0;j--){
//cout << d[s[j]] << endl;
ans+=d[s[j]]*pow(t,len-1-j);
//cout << ans << endl;
}
}
//cout << ans << endl;
string mj;
do{
mj+=x[ans%m];
ans/=m;
}while(ans!=0);
reverse(mj.begin(), mj.end());
cout << mj;
}
406循环子串
思路
若P r e v e r s e P_{reverse}P
reverse
是P的循环字串,则P中的任何一个字串经过右移都可以变成P r e v e r s e P_{reverse}P
reverse
中的一个字串,也就是P的一个字串。那么我们只需要判断P r e v e r s e P_{reverse}P
reverse
是不是P的循环字串,如果是的话,我们就输出"YES",否则就输出"NO"
#include <bits/stdc++.h>
using namespace std;
int t,n;
string s;
int main(){
cin >> t;
for(int i = 1; i <= t; i++){
cin >> n >> s;
string ss = s+s;
reverse(s.begin(), s.end());
int flag = 0;
for(int j = 0; j <= n; j++){
string sub = ss.substr(j,n);
if(sub == s){
flag = 1;
break;
}
}
if(flag==1) cout << "YES" << endl;
else cout << "NO" << endl;
}
}