T1 plan
这题很简单,按规则模拟即可,只是要注意几点
1.我们减的是x,除的是2
2.我们如果要逆着求(n-max(n/2,x)),记得n/2要加上(n%2),因为是向下取整;
T2 string
这题又是一道暴力易但正解难的题
方法1:暴力 O(n*len)//len就是s.size();
每次修改O(n)*判回文O(len)
暴力大家都会就不放代码了
方法2:处理增量O(n+len)
先对原本的字符串找出它不对称的数量。
现在修改就只有三种了
1.当它的len为奇数时,修改中间的(s[n/2])字符等于没修改
2.当s[x] == s[y] and s[y] != c 则多了一个不对称的,记不对称的变量++;本来对称,改了不对称的情况(c是要修改的字符,x是修改位置,y是x的对称位置)
3 当s[x] != s[y] and s[y] == c 则少了一个不对称的,记不对称的变量--;本来不对称,改了对称的情况
当不对称的变量为0时cout<<"Yes\n";
否则cout << "No\n";
放代码
void hw1(string s){
int len=s.size()-1;
int lt=0,rt=len;
while(lt<=rt){
if(s[lt] != s[rt]){
zhu_shu++;
}
lt++;
rt--;
}
}
void work(){
cin >> x >> c;
int y=s.size()-x;
x--;
if(s.size() % 2 == 1 and x == s.size()/2){
if(!zhu_shu){
cout << "Yes\n";
return;
}else{
cout << "No\n";
return;
}
}
if(s[x] == s[y] and s[y] != c){
zhu_shu++;
}
if(s[x] != s[y] and s[y] == c){
zhu_shu--;
}
s[x]=c;
if(!zhu_shu){
cout << "Yes\n";
return;
}
cout << "No\n";
}
T4 picutre
(第三题有点难,最后讲)
这题是一道DP题
先来讲未优化版
状态:dp[i]表示第i天更换1次壁纸的方案数
答案:dp[1]+...+dp[n];
状态转移:
for(int i=1;i<=n;i++){
for(int j=i+a[i];j<=n;j++){
dp[j]+=dp[i];
}
}
初始状态:dp[i]=1;
时间复杂度O(n*n)
优化:
1.第i天更换壁纸影响之后的天数,只有i+a[i]之后才能换;
2倒序枚举状态
for(int i=n;i>=1;i--){
for(int j=i+a[i];j<=n;j++){
dp[i]+=dp[j];
}
}
初始状态 dp[i] = 1;
这样一改就可以用后缀和了
dp[i] = dp[i+1] + ..... + dp[n];
3.维护关于dp的后缀和
sum[i]表示dp[i+1]加到dp[n];
for(int i=n;i>=1;i--){
dp[i]+=(sum[i+a[i]])%mod;
sum[i]=(sum[i+1]+dp[i])%mod;
}
T3 maze
这题目有亿点点难度(对于我)
直接讲正解吧
首先我们正背面各维护一个优先队列(用来求正反反转的最优情况)
1.c==0时,正面, a[i]是正数就加
2.c==1时,背面,a[i]是正数也要走
3 c==0,且a[i] > 0时,计算对正面和背面的贡献(存入优先队列可保证最优)
正面损失a[i]以及代价b[i]
背面增加a[i]以及付出代价b[i]
4 c==1,且a[i] > 0时,计算对正面和背面的贡献
正面增加a[i]以及代价b[i]
背面损失a[i]以及代价b[i]
5 a[i]为负数,翻转后无论正背,都不会走此格,只付出代价(可以为负数)
6 计算翻转格子对正面的前m大的贡献,累加到z(z表示正面,f表示反面)
7 计算翻转格子对正面的前m大的贡献,累加到f(z表示正面,f表示反面)
8 为了最大,f和z要取max;
上AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+88;
#define int long long
int n,res0=0,res1=0;
priority_queue<int> p1, p0;
int a[N],b[N],m,t=0;
bool c;
signed main(){
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> a[i];
}
for(int i=1;i<=n;i++){
cin >> b[i];
}
for(int i=1;i<=n;i++){
cin >> c;
if(c){
res1+=max(t,a[i]);
}else{
res0+=max(t,a[i]);
}
if(c == 0 and a[i] > 0){
p1.push(a[i]-b[i]);
p0.push(-a[i]-b[i]);
}else if(c == 1 and a[i] > 0){
p0.push(a[i]-b[i]);
p1.push(-a[i]-b[i]);
}else if(a[i] < 0){
p1.push(-b[i]);
p0.push(-b[i]);
}
}
int tmp = 0;
int tmpp;
while(tmp<m and !p0.empty()){
tmpp = p0.top();
p0.pop();
if(tmpp <= 0){
break;
}
res0+=tmpp;
tmp++;
}
tmp=0;
while(tmp<m and !p1.empty()){
tmp++;
tmpp = p1.top();
p1.pop();
if(tmpp <= 0){
break;
}
res1+=tmpp;
}
cout << max(res1,res0);
return 0;
}
切记切记要开long long;