传送门
题意:给一个排列,有两种操作:
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=1110;
int f[N*2],que[N*2],a[N*2];
int n;
int get_max(int num,int top)
{
int l=0;
int r=top+1;
while(r-l>1)
{
int mid=(l+r)>>1;
if(a[que[mid]]<num) l=mid;
else r=mid;
}
if(l>top) l=top;
return que[l];
}
int solve(int l)
{
que[0]=0;
int top=0;
for(int j=0;j<n;j++)
{
int x=l+j;
int y=get_max(a[x],top);
f[x]=f[y]+1;
if(a[x]<a[que[f[x]]]||f[x]>top)
{
que[f[x]]=x;
top=max(top,f[x]);
}
}
int ans=0;
for(int j=0;j<n;j++)
ans=max(ans,f[l+j]);
return n-ans;
}
int main()
{
scanf("%d",&n);
int ans=n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
a[i+n]=a[i];
for(int l=1;l<=n;l++)
ans=min(ans,solve(l));
printf("%d",ans);
return 0;
}
签到题。
模拟即可。
题意:f(n,m)表示在n*m的网格中填入H、G、E三种字符,每个H的四联通位置至少有一个G和一个E。求 l i m n → ∞ l i m m → ∞ f ( n , m ) lim _ {n→∞}lim_{m→∞}f(n,m) limn→∞limm→∞f(n,m)
思路:
画几个试试,好像答案在0.5附近,那么极限是不是趋近于0.5呢?
0.5???
WA!!!
观察上面的构造方法,发现中间的H四周有两个H两个E,太浪费了。但是……好像没法让每一个都完美地不浪费……
回头看, l i m n → ∞ l i m m → ∞ lim _ {n→∞}lim_{m→∞} limn→∞limm→∞,那么我们可以直接构造一个无穷大的棋盘!
按照下面方式去画一个3*4的棋盘,我们发现,边界上的H无法满足要求,没关系,棋盘再向外扩张一圈就可以了,因为棋盘无穷大!!!
所以答案就是0.666667。
DP + 细节
题意:输入一段代码,代码中某些片段可能有两种风格。将其用以下方式连缀,求连缀后的最小长度。注意,如果某句话同时出现在两种风格中,那么既可以放到两部分中,也可以合在一起。
#ifdef branch1
#ifdef branch2
#else
#endif
输入:
#include
using namespace std;
int main() {
int a, b;
<<<<<<< branch1
cin >> a >> b;
=======
scanf("%d%d", &a, &b);
>>>>>>> branch2
if (a < 0 || b < 0) return 1;
<<<<<<< branch1
cout << a + b << endl;
=======
printf("%d\n", a + b);a
>>>>>>> branch2
}
输出:
#include
using namespace std;
int main() {
int a, b;
#ifdef branch1
cin >> a >> b;
if (a < 0 || b < 0) return 1;
cout << a + b << endl;
#else
scanf("%d%d", &a, &b);
if (a < 0 || b < 0) return 1;
printf("%d\n", a + b);a
#endif
}
思路:DP
将输入处理成branch1、branch2两份完整的代码,思考如何合并代价最少。
f[i][j][0/1/2]表示处理了branch1的前i行,branch2的前j行,目前输出为合并部分、branch1、branch2的最少代价。如果切换输出状态,代价+1。
#include
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
const int N = 4010;
const LL base = 37;
const LL mod = 1e9 + 7;
short f[N][N][3], pre[N][N][3], que[N * 2];
string str[2][N];
LL h[2][N];
int n = 0,m = 0;
LL get_hash(int opt, int id)
{
int l = str[opt][id].size();
LL now = 0;
for(int i = 0; i < l; i++)
now = (now * base % mod + (LL)str[opt][id][i]) %mod;
return now;
}
void input()
{
int opt = 0;
string s;
while(getline(cin, s))
{
if(s=="<<<<<<< branch1")
{
opt = 1;
continue;
}
if(s=="=======")
{
opt = 2;
continue;
}
if(s==">>>>>>> branch2")
{
opt = 0;
continue;
}
if(opt != 2)
str[0][n++] +=s;
if(opt != 1)
str[1][m++] +=s;
}
for(int i = 0; i < n; i++)
h[0][i + 1] = get_hash(0, i);
for(int i = 0; i < m; i++)
h[1][i + 1] = get_hash(1, i);
}
void dp()
{
memset(f, 0x3f, sizeof(f));
memset(pre,0x3f,sizeof(pre));
f[0][0][0] = 0;
for(int i = 0; i <= n; i++)
for(int j = 0; j <= m; j++)
for(int opt = 0; opt < 3; opt++)
{
if(f[i][j][opt] + 1 + (short)(opt != 1) < f[i + 1][j][1])
{
f[i + 1][j][1] = f[i][j][opt] + 1 + (short)(opt != 1);
pre[i + 1][j][1] = opt;
}
if(f[i][j][opt] + 1 + (short)(opt != 2) < f[i][j + 1][2])
{
f[i][j + 1][2] = f[i][j][opt] + 1 + (opt != 2);
pre[i][j + 1][2] = opt;
}
if(h[0][i + 1] == h[1][j + 1] && f[i][j][opt] + 1 + (short)(opt != 0) < f[i + 1][j + 1][0])
{
f[i + 1][j + 1][0] = f[i][j][opt] + 1 + (opt != 0);
pre[i + 1][j + 1][0] = opt;
}
}
}
void output()
{
int x = n + 1, y = m + 1, z = 0, top = 0;
int cnt = 0;
while(x || y)
{
int pz = pre[x][y][z];
if(z == 0){ x--; y--;}
if(z == 1) x--;
if(z == 2) y--;
que[top] = z;
top++;
z = pz;
}
top--;
x = 0; y = 0;
for(int i = top; i > 0; i--)
{
if(que[i] == 0)
{
if(que[i + 1] != 0) printf("#endif\n");
cout<< str[0][x] << endl;
x++; y++;
}
if(que[i] == 1)
{
if(que[i + 1] == 0) printf("#ifdef branch1\n");
if(que[i + 1] == 2) printf("#else\n");
cout<< str[0][x] << endl;
x++;
}
if(que[i] == 2)
{
if(que[i + 1] == 0) printf("#ifdef branch2\n");
if(que[i + 1] == 1) printf("#else\n");
cout<< str[1][y] << endl;
y++;
}
}
if(que[1] != 0)
printf("#endif\n");
}
int main()
{
input();
dp();
output();
return 0;
}