C-Lexicographically Largest
题意:
思路:
思考可以发现不同的数( )可以从后往前拿不影响,但如果有相同的数,比如3 3,先拿后再拿前得到的数组为3,先拿钱再拿后为3 2
因此对于相同的两个数看作一个区间,区间内可以拿取r-1位置的数将r的数减1,可以从后往前枚举,判断当前数是否出现过,出现过则减去出现次数直至没出现过(需要路径压缩,否则会tle),直至没出现过,扔进数组
时间复杂度:
cpp
void solve(){
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
vector<ll> ans;
map<ll,int> cnt;
for(int i=n;i>=1;i--){
ll x=a[i]+i;
while(1){
if(cnt[x]){
ll y=x;
cnt[y]+=cnt[x-cnt[x]];
x-=cnt[x];
}
else{
ans.push_back(x);
break;
}
}
cnt[x]++;
}
sort(ans.begin(),ans.end(),greater<>());
for(auto it:ans)cout<<it<<" ";
cout<<"\n";
}优化:其实就是按 排序,每次 (但是排序有log复杂度,最终复杂度一样)
D-Sum over all Substrings
题意: 均为01串
有一个模式串p,定义一个字符串q为p-good:
思路:
- 简单版:暴力枚举每个子串,分析如何判断,发现对于一个
q只需要管1的位置放在哪,一个1可以照顾模式串的 的区间;每次枚举到当前i时,判断是否有覆盖,没有则在i+1放一个1,复杂度 - 困难版:考虑dp,
- 在
i+1位置上放,则 都不用考虑了,状态从i+3转移过来,以i为前缀的字符串有n-i+1个,每个增加1贡献
cpp
void solve(){
int n;
cin>>n;
ll ans=0;
vector<ll> dp(n+10);
string s;
cin>>s;
s=" "+s;
for(int i=n;i>=1;i--){
if(s[i]=='0')dp[i]=dp[i+1];
else dp[i]=dp[i+3]+n-i+1;
ans+=dp[i];
}
cout<<ans<<"\n";
}