您的位置:首页 > 其它

something about Educational Codeforces Round 11

2016-06-27 00:20 295 查看
  这场CF的E、F两题最近才补,拿来说说。比较有意思的是,官方题解给的都不是最优复杂度。。

E. Different Subsets For All Tuples

  这道题肯定是dp,我的做法是这样的。假设你现在拥有了一个长度为i的,由m种字符(或部分)组成的串,然后在最后面添加一个字符’a’,会发生什么呢?我们令’a’具有一般性,用’x’代表除了’a’以外的字符。。比如当前串是”xxaxxxaxxx”,由于我们可以在该串的所有子序列后面选择添加或不添加这个’a’,相当于子序列个数翻倍了。但是实际上会造成一些重复,思考下发现只要减去原串中最后一个’a’之前的部分(”xxaxxx”)就好了。

  由于每次可以添加m种字符,所以长度每增加1,答案将乘上m,再乘上2,再减去那些重复计数的部分。

  但是到底有多少重复计数了呢,可以发现,m种可添加的字符里面,有m−1种并不会改变原来的最后一个’a’的位置,于是需要减去的部分每次需要乘上m−1。这样就得到了递推方案。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const ll mod = 1e9+7;

ll dp[1000010];

int main(){
int n,m;
cin>>n>>m;
dp[0] = 1;
ll sub = 0;
for(int i=1;i<=n;i++){
dp[i] = dp[i-1] * m * 2;
sub *= (m-1);
if(i>1){
sub += dp[i-2];
}
sub %= mod;
dp[i] -= sub * m;
dp[i] %= mod;
}

cout<<(dp
+ mod)%mod<<endl;

return 0;
}


F. Bear and Bowling 4

  分治,合并的复杂度,就是计算起点和终点横跨左右两半的复杂度。对于给定的左右端点,它的答案是一个形如x+k∗y的式子,其中x和y由右端点决定,k由左端点决定。最优的合并方案是枚举左边,然后利用右边的凸壳迅速得到每个左端点对应的最优右端点。最近怎么写什么题都要凸壳= =

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int maxn = 200010;
const ll INF = 2e18;

ll a[maxn];
ll sum[maxn];
ll incSum[maxn];
ll sufSum[maxn];

struct Point{
ll x;
ll y;
int id;
Point(ll x,ll y,int id):x(x),y(y),id(id){
}
Point(){
}
bool operator<(const Point& other)const{
if(x!=other.x){
return x<other.x;
}
return y>other.y;
}
}pts[maxn];

Point ch[maxn];
int sz;

ll solve(int l,int r){
if(l==r){
return a[l];
}
int mid = (l+r)>>1;
ll res = max(solve(l,mid),solve(mid+1,r));
int k = 1;
for(int i=mid+1;i<=r;i++,k++){
pts[k].x = pts[k-1].x + a[i];
pts[k].y = pts[k-1].y + a[i] * k;
pts[k].id = i;
}
sort(pts+1,pts+k);
//Convex Hull
sz = 0;
for(int i=1;i<k;i++){
if(i>1 && pts[i].x == pts[i-1].x){
continue;
}
if(sz<2){
ch[sz++] = pts[i];
}else{
while(sz>1 && (pts[i].y-ch[sz-1].y+0.0)*(ch[sz-1].x-ch[sz-2].x) >=
(ch[sz-1].y-ch[sz-2].y+0.0)*(pts[i].x-ch[sz-1].x) ){
sz--;
}
ch[sz++] = pts[i];
}
}

ll part1 = 0;
int best = 0;
for(int i=mid;i>=l;i--){
part1 += sufSum[mid] - sufSum[i-1];
ll C = (mid - i + 1);
ll part2 = -INF;
ll cur;
while(best<sz){
cur = ch[best].x*C + ch[best].y;
if(cur > part2){
part2 = cur;
best++;
}else{
break;
}
}
best--;
res = max(res,part1+part2);
}
return res;
}

int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%I64d",&a[i]);
sufSum[i] = sufSum[i-1] + a[i];
}

ll ans = solve(1,n);
if(ans < 0) ans = 0;

cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces