1407:快速找出最小數
題意
給定一個大小爲N 的整數數組array,我們定義兩種操作:
1) Add(L, R, W)。即將子數組[L, R]中的元素,都累加一個整數W。
2) Min(L, R)。即返回子數組[L, R]之中,最小的一個元素的值。
其中L和R爲數組的下標,且從0開始計數。當數組下標L > R時,我們認爲這個子數組的元素包含array[L], array[L+1], … array[N – 1], array[0], array[1], … array[R]。
思路
區間查詢最小值問題,一般用線段樹來解決,對於要求不高的,還可以用分桶法(也就是平方分割)。
代碼
#include <stdio.h>
#include <limits.h>
#define N 100000
#define M 100
#define INF INT_MAX
int a[N];
int seg[4*N];
int add[4*N];
int min(int x, int y)
{
return (x < y) ? x : y;
}
void pullup(int i)
{
seg[i] = min(seg[2*i], seg[2*i+1]);
}
void pushdown(int i)
{
if (add[i])
{
add[2*i] += add[i];
add[2*i+1] += add[i];
seg[2*i] += add[i];
seg[2*i+1] += add[i];
add[i] = 0;
}
}
void create(int i, int b, int e)
{
add[i] = 0;
if (b == e)
{
seg[i] = a[b];
return;
}
create(2*i, b, (b+e)/2);
create(2*i+1, (b+e)/2+1, e);
pullup(i);
}
void update(int w, int i, int b, int e, int l, int r)
{
//printf("%d %d %d %d %d\n", i, b, e, l, r);
//printf("=====");
//for (int j=0; j<11; j++)
// printf("%d ", seg[j]);
//printf("\n");
//for (int j=0; j<11; j++)
// printf("%d ", add[j]);
//printf("\n");
if (b > r || e < l)
return;
if (l <= b && e <= r)
{
add[i] += w;
seg[i] += w;
return;
}
pushdown(i);
update(w, 2*i, b, (b+e)/2, l, r);
update(w, 2*i+1, (b+e)/2+1, e, l, r);
pullup(i);
}
int getMin(int i, int b, int e, int l, int r)
{
if (b > r || e < l)
return INF;
if (l <= b && e <= r)
{
return seg[i];
}
pushdown(i);
int m1 = getMin(2*i, b, (b+e)/2, l, r);
int m2 = getMin(2*i+1, (b+e)/2+1, e, l, r);
//pullup(i);
return min(m1, m2);
}
int main(void)
{
int n, i, m;
char s[M];
int l, r, w;
while (scanf("%d", &n) != EOF)
{
for (i=0; i<n; i++)
scanf("%d", &a[i]);
create(1, 0, n-1);
scanf("%d", &m);
getchar();
for (i=0; i<m; i++)
{
scanf("%d%d", &l, &r);
gets(s);
if (s[0] == '\0')
{
if (l > r)
{
int m1 = getMin(1, 0, n-1, l, n-1);
int m2 = getMin(1, 0, n-1, 0, r);
printf("%d\n", min(m1, m2));
}
else
printf("%d\n", getMin(1, 0, n-1, l, r));
}
else
{
sscanf(s, "%d", &w);
if (l > r)
{
update(w, 1, 0, n-1, l, n-1);
update(w, 1, 0, n-1, 0, r);
}
else
update(w, 1, 0, n-1, l, r);
}
}
}
return 0;
}
/**************************************************************
Problem: 1407
User: liangrx06
Language: C
Result: Accepted
Time:360 ms
Memory:4432 kb
****************************************************************/
1408:吃豆機器人
題意
淘寶公司內部有許多新鮮的小玩具,例如淘寶智能機器人。小時候,大家都玩過那個吃豆子的遊戲吧,這機器人就是按照這個遊戲設計的,它會朝着豆子的方向行走。不過機器人還存在一個bug,他只會朝南和朝東走。現在有一塊空地,分成了n*m個格子,每個格子內有一顆豆子。機器人的起點在西北角,終點在東南角。請問機器人從起點到終點有多少種不同的方法。
思路
簡單的DP。但其實也可以直接用組合數公式來給出答案,但是n和m太大,目前還沒有掌握這種大組合數取模的計算方法。
代碼
#include <stdio.h>
#include <string.h>
#define N 1000
#define M 10009
int main(void)
{
int n, m, i, j;
int a[N+1][N+1];
memset(a, 0, sizeof(a));
for (i=1; i<=1000; ++i)
a[1][i] = a[i][1] = 1;
for(i=2; i<=N; i++)
{
for (j=2; j<=N; j++)
{
a[i][j] = (a[i-1][j]+a[i][j-1]) % M;
}
}
while (scanf("%d%d", &n, &m) != EOF)
{
printf("%d\n", a[n][m]);
}
return 0;
}
/**************************************************************
Problem: 1408
User: liangrx06
Language: C
Result: Accepted
Time:20 ms
Memory:4752 kb
****************************************************************/
1409:TBString
題意
淘寶公司內部有一個字符串小王子,他平常無聊就研究字符串。一天,他在研究字符串TBTBBT時,他定義了一個統計函數F,F(S)表示一個字符串當中S出現的次數。對於字符串TBTBBT,那麼就有F(T)=3,F(B)=3,F(TB)=2,F(BT)=2。但如果我們已知F(T),F(B),F(TB)和F(BT)這四個值,你能求出滿足這4個條件,同時字典序最小的字符串麼?若存在,則輸出這個字符串;若不存在,則輸出-1。
值得注意的是,字符串小王子認爲T是比B小的,因爲如果B比T小,那麼字符串開頭可能就會是BTTB,哈哈,你們邪惡了吧。
思路
這個題應該屬於DP,思路上並不難,但真的好麻煩,需要注意各種可能的情況。所幸竟然一遍AC了,不然真是錯了都不想查。
代碼
#include <stdio.h>
int main()
{
int i;
int t, b, tb, bt;
char s[2000001];
while (scanf("%d%d%d%d", &t, &b, &tb, &bt) != EOF) {
int flag = 1;
if (tb == bt) {
if (t < tb || b < tb)
flag = 0;
else if (t == tb && b == tb)
flag = 0;
else if (t == tb) {
int k = 0;
for (i = 0; i < t; i ++)
s[k++] = 'B', s[k++] = 'T';
for (i = 0; i < b-tb; i ++)
s[k++] = 'B';
s[k] = '\0';
}
else {
int k = 0;
for (i = 0; i < t-tb; i ++)
s[k++] = 'T';
for (i = 0; i < tb; i ++) {
s[k++] = 'B';
if (i == tb-1) {
for (int j = 0; j < b-tb; j ++)
s[k++] = 'B';
}
s[k++] = 'T';
}
s[k] = '\0';
}
}
else if (tb > bt) {
if (tb != bt+1 || t < tb || b < tb)
flag = 0;
else {
int k = 0;
for (i = 0; i < t-tb; i ++)
s[k++] = 'T';
for (i = 0; i < tb; i ++)
s[k++] = 'T', s[k++] = 'B';
for (i = 0; i < b-tb; i ++)
s[k++] = 'B';
s[k++] = '\0';
}
}
else {
if (tb != bt-1 || t < bt || b < bt)
flag = 0;
else {
int k = 0;
for (i = 0; i < bt; i ++) {
s[k++] = 'B';
if (i == bt-1) {
for (int j = 0; j < b-bt; j ++)
s[k++] = 'B';
}
s[k++] = 'T';
if (i == 0) {
for (int j = 0; j < t-bt; j ++)
s[k++] = 'T';
}
}
s[k] = '\0';
}
}
if (flag == 0)
puts("-1");
else
puts(s);
}
return 0;
}
/**************************************************************
Problem: 1409
User: liangrx06
Language: C
Result: Accepted
Time:90 ms
Memory:2792 kb
****************************************************************/
1410:壘積木
題意
給你一些長方體的積木,問按以下規則能最多壘幾個積木。
1 一個積木上面最多隻能壘另一個積木。
2 在下面的積木的長寬高要大於或等於上面的積木的長寬高
思路
開始沒有想到用DP,沒有好的思路。看到別人用DP才發現好簡單。
代碼
#include <stdio.h>
#include <string.h>
#define N 1000000
#define M 100
int max(int a, int b)
{
return (a>b) ? a : b;
}
int dp[M+1][M+1][M+1];
int count[M+1][M+1][M+1];
int main(void)
{
int n, i, j, k, r, m;
int len, wid, heig;
while (scanf("%d", &n) != EOF)
{
memset(count, 0, sizeof(count));
for (i=0; i<n; i++)
{
scanf("%d%d%d", &len, &wid, &heig);
count[len][wid][heig] ++;
}
memset(dp, 0, sizeof(dp));
m = 0;
for (j=1; j<=M; j++)
{
for (k=1; k<=M; k++)
{
for (r=1; r<=M; r++)
{
dp[j][k][r] = max(max(dp[j-1][k][r], dp[j][k-1][r]),
dp[j][k][r-1]) + count[j][k][r];
m = max(m, dp[j][k][r]);
}
}
}
printf("%d\n", m);
}
return 0;
}
/**************************************************************
Problem: 1410
User: liangrx06
Language: C
Result: Accepted
Time:1210 ms
Memory:8964 kb
****************************************************************/
1411:轉圈
題意
在一個有向圖有n個頂點(編號從1到n),給一個起點s,問從起點出發,至少經過一條邊,回到起點的最短距離。
思路
主體用dijkstra算法求解,但題目要求至少經過一條邊,所以應該將起點直接相連的所有邊初始化賦值距離,其它的(包括起點)賦值無窮大。
代碼
#include <stdio.h>
#include <string.h>
#define INF 100000000
#define N 501
int main()
{
int n, m, s, a, b, c, map[N][N], len[N], used[N];
while (scanf("%d%d%d", &n, &m, &s) != EOF)
{
memset(map, 0, sizeof(map));
while (m--)
{
scanf("%d%d%d", &a, &b, &c);
if (map[a][b]==0 || map[a][b]>c)
map[a][b] = c;
}
for(int i=1; i<=n; i++)
if(map[s][i] != 0)
len[i] = map[s][i];
else
len[i] = INF;
int index, min;
memset(used, 0, sizeof(used));
while(1)
{
min = INF, index = -1;
for(int i=1; i<=n; i++)
if(!used[i] && len[i] < min)
min = len[i], index = i;
if(index == -1 || index == s)
break;
used[index] = 1;
for(int i = 1;i <= n; i++)
if(!used[i] && map[index][i] && len[i] > len[index] + map[index][i])
len[i] = len[index] + map[index][i];
}
if(index == -1)
printf("help!\n");
else
printf("%d\n", len[s]);
}
}
/**************************************************************
Problem: 1411
User: liangrx06
Language: C
Result: Accepted
Time:120 ms
Memory:1828 kb
****************************************************************/