HDU 5583 Kingdom of Black and White
Description
In the Kingdom of Black and White (KBW), there are two kinds of frogs: black frog and white frog.
Now N frogs are standing in a line, some of them are black, the others are white. The total strength of those frogs are calculated by dividing the line into minimum parts, each part should still be continuous, and can only contain one kind of frog. Then the strength is the sum of the squared length for each part.
However, an old, evil witch comes, and tells the frogs that she will change the color of at most one frog and thus the strength of those frogs might change.
The frogs wonder the maximum possible strength after the witch finishes her job.
Input
First line contains an integer T, which indicates the number of test cases. Every test case only contains a string with length N, including only 0 (representing a black frog) and 1 (representing a white frog). ⋅1≤T≤50⋅ . for 60% data, 1≤N≤1000. . for 100% data, 1≤N≤105. ⋅ the string only contains 0 and 1.
Output
For every test case, you should output " Case #x: y",where x indicates the case number and counts from 1 and y is the answer.
Sample Input
2 000011 0101
Sample Output
Case #1: 26 Case #2: 10
題意
給你一個只含01的字串,你可以至多翻轉其中的一個字元 (0->1,1->0),使得它的strength值最大。 strength值的計算方法:將連續的並且相同的字元放在一起,構成多個子字串,由每個子字串的長度可得一個長為n的序列s,該字串strength值為s序列每個數的平方和。
思路
- 改變相鄰兩個數a,b,大的數加1,小的數減1。
- 改變相鄰三個數a,1,b,並且中間的數為1。把中間那個數所代表的字元翻轉後,前後字串就相連了,子字串的長度為a+1+b。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <stack>
#include <cmath>
#include <deque>
#include <vector>
#define N 1000005
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long int LL;
int main()
{
int T,z=0;
scanf("%d",&T);
while(T--)
{
vector<LL>v,w;
deque<char>p;
char s[N]= {0};
LL sum1=0,sum2=0;
scanf(" %s",s);
for(LL i=0; s[i]; i++)
{
if(p.empty())
{
p.push_back(s[i]);
continue;
}
if(p.back()!=s[i])
{
v.push_back((LL)p.size());
w.push_back((LL)p.size());
p.clear();
p.push_back(s[i]);
}
else
{
p.push_back(s[i]);
}
}
if(p.size()!=0)
{
v.push_back((LL)p.size());
w.push_back((LL)p.size());
}
LL pos=0,maxs=0;
for(LL i=1; i<(LL)v.size(); i++)
{
if( (LL)(2*abs(v[i-1]-v[i])+2) > maxs)
{
pos=i;
maxs=(LL)(2*abs(v[i-1]-v[i])+2);
}
}
if(pos!=0)
{
if(v[pos]>v[pos-1])
{
v[pos]++;
v[pos-1]--;
}
else
{
v[pos]--;
v[pos-1]++;
}
}
for(LL i=0; i<(LL)v.size(); i++)
{
sum1+=v[i]*v[i];
}
pos=0;
maxs=0;
for(LL i=1; i<(LL)w.size()-1; i++)
{
if(w[i]==1)
{
if( (2*(w[i-1]+w[i+1])+2*w[i-1]*w[i+1]) > maxs )
{
pos=i;
maxs=(2*(w[i-1]+w[i+1])+2*w[i-1]*w[i+1]);
}
}
}
if(pos!=0)
{
for(LL i=0; i<(LL)w.size(); i++)
{
if(i==pos-1)
{
sum2+=(w[i]+w[i+1]+w[i+2])*(w[i]+w[i+1]+w[i+2]);
i+=2;
}
else
sum2+=w[i]*w[i];
}
}
printf("Case #%d: %lld\n",++z,(long long)max(sum1,sum2));
}
return 0;
}
看其他博主,還有一種類似dp的寫法:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <stack>
#include <cmath>
#include <deque>
#include <vector>
#define N 1000005
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long int LL;
int main()
{
int T,z=0;
scanf("%d",&T);
while(T--)
{
vector<LL>v,w;
deque<char>p;
char s[N]= {0};
LL sum=0,ans=0;
scanf(" %s",s);
for(LL i=0; s[i]; i++)
{
if(p.empty())
{
p.push_back(s[i]);
continue;
}
if(p.back()!=s[i])
{
v.push_back((LL)p.size());
p.clear();
p.push_back(s[i]);
}
else
{
p.push_back(s[i]);
}
}
if(p.size()!=0)
{
v.push_back((LL)p.size());
}
for(LL i=0;i<v.size();i++)
sum+=v[i]*v[i];
ans=sum;
for(int i=1;i<v.size();i++)
{
if(v[i]==1 && i!=v.size()-1)
{
ans=max(ans,sum+2*(v[i-1]+v[i+1])+2*v[i-1]*v[i+1]);
}
else
{
ans=max(ans,sum+2*abs(v[i]-v[i-1])+2);
}
}
printf("Case #%d: %I64d\n",++z,ans);
}
return 0;
}
總結
求連續三個數的時候,把三個數的和的平方當做判斷是否修改這三個值得依據,其實應該是把改變這三個值之後能帶來的增量當做判斷條件。 dp的寫法挺好的,找到最優解就行了,就是原陣列的sum+最大增量。