题目传送门:
A题:
首先我想到的是用模拟,每次从n个数中选一个最大的,删掉,但是这样对于21435 1 这组数据运行结果是2143 显然正确结果应该是1435,然后又想到如果第一个数比第二个数大3,就先删掉第一个数,这样还有一个问题就是第一个数跟第二个数相同的时候删不删,对于22345显然不应该删第一个,对于22135又要删第一个,这样WA了几法,果断pass掉这种做法。
然后又参考了http://blog.csdn.net/lyhvoyage/article/details/38379685的做法:
1.从1 -- m+1 中取最小的,记录位置为pos,
2.从pos+1 -- m+2 中选最小的,记录位置;
3.以此类推.....
算了一下复杂度可以直接用朴素算法算最小值;
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
char s[1010];
char ans[1020];
int st[1010][20];
int Min(int x,int y)
{
return s[x] <= s[y] ? x : y;
}
void RMQ_Init(int len)
{
for(int i = 0; i < len; i++)
st[i][0] = i;
for(int j = 1; (1<<j) < len; j++)
for(int i = 0; i+(1<<j)-1 < len;i++)
st[i][j] = Min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int Query(int l,int r)
{
int k = (int)(log((double)(r-l+1))/log(2.0));
return Min(st[l][k],st[r-(1<<k)+1][k]);
}
int main()
{
int len, m, i;
while(scanf("%s%d",s, &m)!=EOF)
{
len = strlen(s);
RMQ_Init(len);
m = len - m;
int pos = 0, num = 0;
while(m--)
{
pos = Query(pos, len - m - 1);
ans[num++] = s[pos++];
}
for(i = 0; i < num; i++)
if(ans[i]!='0')
break;
if(i == num)
printf("0");
else
{
while(i < num)
printf("%c",ans[i++]);
}
puts("");
}
return 0;
}
B题;
st算法,但是要优化,k的值为1e9而v[i] 最大只有1000; 因此要先用k除以最大的v[i],当做m的初始值,但是要注意 max_v 有可能为0 , 除完之后 m也有可能为0;
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int MaxN = 200000 + 5;
int a[MaxN];
int n, k;
int dp[MaxN][19];
void rmq_st()
{
for(int i=0; i<n; ++i)dp[i][0] = a[i];
int m = (int) (log(1.0 * n) / log(2.0));
for(int j=1; j<=m; ++j){
int t = n - (1 << j) + 1;
for(int i=0; i<t; ++i){
dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
}
}
}
inline int rmq_query(int l, int r)
{
int k = (int) (log(1.0 * (r - l + 1)) / log(2.0));
return (max(dp[l][k], dp[r - (1 << k) + 1][k]));
}
int main()
{
while(~scanf("%d%d", &n, &k) && n > -1){
int a_max = 0;
for(int i=0; i<n; ++i){
scanf("%d", &a[i]);
if(a[i] > a_max) a_max = a[i];
}
rmq_st();
bool isok = false;
if(a_max == 0){printf("-1"); continue;}
int m = k / a_max;
if(m == 0){printf("1\n"); continue;}
for(; m<=n; ++m){
int sum = 0;
int len = n / m;
int l;
for(int i=0; i<m; ++i){
l = i * len;
sum += rmq_query(l, l + len - 1);
//cout << sum << endl;
if(sum > k){isok = true; break;}
}
if(isok) break;
}
printf("%d\n", isok ? m : -1);
}
return 0;
}
C题:
嗯,很好的ST大法的模板
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int MaxN = 50000 + 5;
int a[MaxN];
int n, q;
int dp[MaxN][17][2]; //0 -> max; 1 -> min;
void rmq_st()
{
for(int i=0; i<n; ++i)dp[i][0][0] = dp[i][0][1] = a[i];
int m = (int) (log(1.0 * n) / log(2.0));
for(int j=1; j<=m; ++j){
int t = n - (1 << j) + 1;
for(int i=0; i<t; ++i){
dp[i][j][0] = max(dp[i][j - 1][0], dp[i + (1 << (j - 1))][j - 1][0]);
dp[i][j][1] = min(dp[i][j - 1][1], dp[i + (1 << (j - 1))][j - 1][1]);
}
}
}
inline void rmq_query(int l, int r, int& mini, int& maxi)
{
int k = (int) (log(1.0 * (r - l + 1)) / log(2.0));
maxi = (max(dp[l][k][0], dp[r - (1 << k) + 1][k][0]));
mini = (min(dp[l][k][1], dp[r - (1 << k) + 1][k][1]));
}
int main()
{
while(~scanf("%d%d", &n, &q)){
for(int i=0; i<n; ++i)
scanf("%d", &a[i]);
rmq_st();
int l, r, mini, maxi;
for(int i=1; i<=q; ++i){
scanf("%d%d", &l, &r);
rmq_query(l - 1, r - 1, mini, maxi);
printf("%d\n", maxi - mini);
}
}
return 0;
}