遊戲玩多了,後悔了,打算戒一下游戲,於是我們可以愉快地繼續做題了
如果這篇裡的題您一眼秒了請不要嘲笑我,我會哭的
好叭其實我已經哭了因為我知道您已經秒掉它們了
P1119 災後重建
試圖每次在圖裡加邊。把邊按照時間排序,時間到了就可以這條邊加到圖裡了,同時連著這條邊的兩個點也可以做Floyed的中轉點了,但是這樣會有不少重複運算,由於邊是實時新增的,還不能設vis標記已經訪問過的點。但其實題意就是直接加點,邊本來就可以用,所以我繞遠了。
TLE 80
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 204;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int n, m, q;
int w[maxn][maxn], t[maxn];
struct node
{
int u, v, w;
bool operator < (const node &T) const
{
return t[u] < t[T.u];
}
}b[20000];
void floyed(int k)
{
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
if(w[i][j] > w[i][k] + w[k][j])
{
w[i][j] = w[i][k] + w[k][j];
}
}
}
}
int main()
{
n = read(); m = read();
for(int i=0; i<n; i++) t[i] = read();
for(int i=1; i<=m; i++)
{
int u = read(), v = read(), h = read();
if(t[u] < t[v]) swap(u, v);//相對較大的一項最小
b[i].u = u; b[i].v = v; b[i].w = h;
}
sort(b+1, b+1+m);
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
w[i][j] = 1e9;
}
w[i][i] = 0;
}
q = read(); int j = 1;
for(int i=1; i<=q; i++)
{
int x = read(), y = read(), tnow = read();
while(j <= m && t[b[j].u] <= tnow)
{
w[b[j].u][b[j].v] = w[b[j].v][b[j].u] = min(w[b[j].u][b[j].v], b[j].w);
//j++; //ntc = 0;
floyed(b[j].v);
floyed(b[j].u);
j++;//我加早了
}
if(w[x][y] == 1e9) printf("-1\n");
else printf("%d\n", w[x][y]);
}
return 0;
}
然後改成新增點就能過了。不過加點和加邊不同的是需要判斷詢問的時刻兩端是否修好,不過這個題目裡也描述了,emmm可見我是不會讀題的。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 204;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int n, m, q;
int w[maxn][maxn], t[maxn];
void floyed(int k)
{
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
if(w[i][j] > w[i][k] + w[k][j])
{
w[i][j] = w[i][k] + w[k][j];
}
}
}
}
int main()
{
n = read(); m = read();
for(int i=0; i<n; i++) t[i] = read();
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++) w[i][j] = 1e9;
w[i][i] = 0;
}
for(int i=1; i<=m; i++)
{
int u = read(), v = read(), h = read();
w[u][v] = w[v][u] = min(w[u][v], h);
}
q = read(); int j = 0;
for(int i=1; i<=q; i++)
{
int x = read(), y = read(), tnow = read();
while(j < n && t[j] <= tnow)
{
floyed(j); j++;
}
if(w[x][y] == 1e9 || t[x] > tnow || t[y] > tnow) printf("-1\n");
else printf("%d\n", w[x][y]);
}
return 0;
}
P1121 環狀最大兩段子段和
WA 80
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5 + 7;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int n, a[maxn], sum[maxn], ans=-1e9, posl, posr, ty;
int l, r, q[maxn];
int main()
{
n = read();
for(int i=1; i<=n; i++) a[i] = read();
for(int i=1; i<=n; i++) a[i+n] = a[i];
for(int i=1; i<=n+n; i++) sum[i] = sum[i-1] + a[i];
l = 1; r = 1;
q[1] = 0;
for(int i=1; i<=n+n; i++)//先找到最大的一段
{
while(l <= r && q[l] < i - n) l++;
if(ans < sum[i] - sum[q[l]])
{
posl = q[l] + 1; posr = i; ans = sum[i] - sum[q[l]];
}
while(l <= r && sum[q[r]] >= sum[i]) r--;
q[++r] = i;
}
int mx = min(n+n, posl+n-1), ans2 = -1e9;
l = 1; r = 1; q[1] = posr;
for(int i=posr+1; i<=mx; i++)
{
ans2 = max(ans2, sum[i] - sum[q[l]]);
while(l <= r && sum[q[r]] >= sum[i]) r--;
q[++r] = i;
}
if(posl == posr) ty = ans + ans2;
else ty = max(ans, ans+ans2);
printf("%d", ty);
return 0;
}
先斷環成鏈再滑動視窗求最大值,在第一次的基礎上再求一次,然後錯了。或許是因為這種東西不能貪心。
然後……鶴了一下I_AM_HelloWord的題解……把 i 之前的最大子段和 i 之後的最大子段相加就可以得到沒有環的答案,而有環的區別就是可以首尾相連,沒選的部分相當於不成環情況下的最小兩段子段,總和減掉最小兩段子段的結果就是另一種可能的情況。如果只有1個正數(其實應該是非負數?)倒過來會出現首尾全選再作差也就是隻選了一個數的情況需要特判。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
const int INF = 0x3f3f3f3f;//1061109567
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int n, sum, tot;
int f[maxn], g[maxn], a[maxn];
int query()//原來兩個最大子段和可以這麼算!!抄完我終於明白了(bushi)
{
int ans = -INF;
for(int i=1; i<=n; i++) f[i] = max(f[i-1], 0) + a[i];
for(int i=n; i>=1; i--) g[i] = max(g[i+1], 0) + a[i];
for(int i=1; i<=n; i++) f[i] = max(f[i-1], f[i]);
for(int i=n; i>=1; i--) g[i] = max(g[i+1], g[i]);
for(int i=1; i<n; i++) ans = max(ans, f[i] + g[i+1]);
return ans;
}
int main()
{
n = read();
memset(f, ~0x3f, sizeof(f));//-1061109568
memset(g, ~0x3f, sizeof(g));
for(int i=1; i<=n; i++)
{
a[i] = read(); sum += a[i]; tot += a[i] >= 0;
}
int t1 = query();
if(tot == 1) printf("%d", t1);
else
{
for(int i=1; i<=n; i++) a[i] = -a[i];
int t2 = sum + query();
if(!t2) t2 = -INF;
printf("%d", max(t1, t2));
}
return 0;
}
P1124 檔案壓縮
NULL
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 7;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int n;
char s[maxn];
struct node
{
char l, r;//首字母和尾字母
int t;//順序
bool operator < (const node &T) const
{
if(l == T.l) return t < T.t;
return l < T.l;
}
}xl[maxn];
int main()
{
n = read();
scanf("%s", s);
for(int i=0; i<n; i++)
{
xl[i+1].l = s[i];
xl[i+1].r = s[(i+n-1)%n];
xl[i+1].t = i;
}
sort(xl+1, xl+1+n);
for(int i=1; i<=n; i++) printf("%c %c\n", xl[i].l, xl[i].r);
printf("\n");
for(int i=1; i<=n; i++)
{
printf("%c", xl[i].r);
}
printf("\n");
for(int i=1; i<=n; i++)
{
if(xl[i].t == 1)
{
printf("%d", i); break;
}
}
return 0;
}
本來打算寫出正向的求法再逆過來,然後不會做了。如果有很小的資料的話我只想到了全排列列舉,小菜是這樣的。
然後忽然有思路了,感覺是對的但是隻有10分,疑似出現了各種越界……(放在這只是為了存檔,沒有儲存程式碼的習慣,晚飯後再研究)
WA 10
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 7;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int n, p;
char s1[maxn], s[maxn], c[maxn];
vector<int> pos[30];
int main()
{
n = read();
scanf("%s", s1);
p = read();
s[0] = s1[p-1];
memcpy(c, s1, sizeof(c));
//printf("%s", c);
sort(c, c+n);
for(int i=n-1; i>=0; i--)
{
if(i == p-1) continue;
pos[s1[i]-'a'+1].push_back(i);
//printf("pos[%c].push_back(%d)\n", s1[i], i);
}
int r = p-1;
for(int i=0; i<n; )
{
s[++i] = c[r];
//printf("c[%d] = %c\n", r, c[r]);
int l = pos[c[r]-'a'+1].size()-1;
//printf("l = %d\n", l);
l = pos[c[r]-'a'+1][l];
//printf("r = %d\n", r);
pos[c[r]-'a'+1].pop_back();
r = l;
//s[++i] = s1[r];
}
s[n] = '\0';
printf("%s", s);
return 0;
}