哎呀~
今年初賽做得太倉促,又犯蠢卡題了,做得不好。
所以現在決定臨時訓練一下!
下面是今年大區賽的題目信息——
前面什麼排序for for for啦,基本stl 搞搞啦,字符串處理啦~
好好讀題,想清楚怎麼樣最好寫,最快寫!
我發現,多關鍵字最短路、最小字典序,這些東西CCCC真的好喜歡出啊>.<
也許練一下會有不錯的提高哦~
這裏貼出幾題代碼——
【2017年團體程序設計天梯賽-大區賽 2-2】【多項式除法 STL-map】多項式A除以B
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m;
map<int, double>a, b, ans;
map<int, double>::iterator it;
void print(map<int, double> &ans)
{
for (it = ans.begin(); it != ans.end(); )
{
if (fabs(it->second) < 0.05)ans.erase(it++);
else it++;
}
if (ans.size() == 0)
{
puts("0 0 0.0");
}
else
{
printf("%d", ans.size());
for (it = --ans.end(); ; --it)
{
printf(" %d %.1f", it->first, it->second);
if (it == ans.begin())break;
}puts("");
}
}
int main()
{
while(~scanf("%d", &n))
{
a.clear();
for (int i = 1; i <= n; ++i)
{
int index; double coeff;
scanf("%d%lf", &index, &coeff);
a[index] += coeff;
}
scanf("%d", &m);
b.clear();
for (int i = 1; i <= m; ++i)
{
int index; double coeff;
scanf("%d%lf", &index, &coeff);
b[index] += coeff;
}
ans.clear();
while (a.size() && b.size())
{
auto A = --a.end();
auto B = --b.end();
double Index = A->first - B->first; if (Index < 0)break;
double k = A->second / B->second;
for (auto it : b)
{
int index = it.first + Index; double coeff = it.second * k;
a[index] -= coeff;
}
for (it = a.begin(); it != a.end(); )
{
if (fabs(it->second) < 0.0001)a.erase(it++);
else it++;
}
ans[Index] += k;
}
print(ans);
print(a);
}
return 0;
}
/*
【trick&&吐槽】
<1> 對於這種離散型的數據,也許最好的方法是使用map等結構
<2> 卡精度、卡精度、卡精度、卡精度、卡精度、卡精度
【題意】
實現多項式除法
【分析】
直接從高項開始,向低項方向處理,一項項處理即可。
*/
【2017年團體程序設計天梯賽-大區賽 3-2】【多關鍵字最短路】周遊世界
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 10010, M = 100 * 100 * 200 * 2, Z = 1e9 + 7, inf = 0x3f3f3f3f;
//最多點數100 * 100
//最多邊數100 * 100 * 100 * 2
typedef pair<int, int>P;
struct Node
{
int x, d1, d2;
bool operator < (const Node & b)const
{
if (d1 != b.d1)return d1 > b.d1;
return d2 > b.d2;
}
};
priority_queue<Node>q;
int casenum, casei;
int num;
int first[N], id;
int w[M], nxt[M], c_d1[M], c_d2[M], c_c[M];
int a[N];
int D1[N], D2[N], C[N], pre[N];
int ST, ED;
void print(int x)
{
if (x == ST)return;
int y = pre[x];
print(y);
printf("Go by the line of company #%d from %04d to %04d.\n", C[x], y, x);
}
void ins(int x, int y, int d1, int d2, int c)
{
w[++id] = y;
nxt[id] = first[x];
c_d1[id] = d1;
c_d2[id] = d2;
c_c[id] = c;
first[x] = id;
}
void inq(int x, int d1, int d2, int c, int y)
{
if (d1 < D1[x] || d1 == D1[x] && d2 < D2[x])
{
D1[x] = d1;
D2[x] = d2;
C[x] = c;
pre[x] = y;
q.push({ x,D1[x], D2[x] });
}
}
bool e[N];
void dijkstra()
{
for (int i = 0; i <= 10000; ++i)
{
e[i] = 0;
D1[i] = inf;
}
while (!q.empty())q.pop();
inq(ST, 0, 0, 0, 0);
while (!q.empty())
{
int x = q.top().x;
int d1 = q.top().d1;
int d2 = q.top().d2;
q.pop(); if (e[x])continue;
if (x == ED)
{
printf("%d\n", D1[x]);
print(ED);
return;
}
e[x] = 1;
for (int z = first[x]; z; z = nxt[z])
{
inq(w[z], D1[x] + c_d1[z], D2[x] + c_d2[z], c_c[z], x);
}
}
puts("Sorry, no line is available.");
}
int main()
{
id = 1;
scanf("%d", &num);
for (int I = 1; I <= num; ++I)
{
int g; scanf("%d", &g);
for (int i = 1; i <= g; ++i)
{
scanf("%d", &a[i]);
if (i != 1)a[i + g - 1] = a[i];
}
int top = a[1] == a[g] ? g + g - 1 : g;
for (int i = 1; i <= g; ++i)
{
for (int j = i + 1; j <= top; ++j)
{
int x = a[i];
int y = a[j];
ins(x, y, j - i, 1, I);
ins(y, x, j - i, 1, I);
}
}
}
int q; scanf("%d", &q);
while (q--)
{
scanf("%d%d", &ST, &ED);
dijkstra();
}
return 0;
}
/*
【trick&&吐槽】
這題給我最大的教訓是——
做題要冷靜,先認真讀題,理清題目要你做什麼
【題意】
有n(100)個聯盟公司。
每個公司有m(100)個停經站。
相鄰的停經站之間的的邊只屬於這一家公司(也就是沒有重邊)。
K(10)次詢問。我們想要使得——
<1> 中途經站最少
<2> 換成次數最少
<3> 記錄路線
【分析】
這顯然是個最短路,最多會有100 * 100個點,於是這裏就應該放棄floyd.
然後我們就最好用dijkstra了。
我們需要記錄一個二維最短路,同時還要記一個前驅
【時間複雜度&&優化】
*/
【2017年團體程序設計天梯賽-大區賽 3-3】【狀壓DP + 貪心】球隊“食物鏈”
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 24, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
char s[N][N];
bool win[N][N];
int n;
int f[1 << 20][20];
int nxt[1 << 20][20];
void print(int sta, int fst)
{
if (fst == 0)return;
printf(" %d", fst + 1);
print(sta ^ 1 << fst, nxt[sta][fst]);
}
void solve()
{
MS(f, 0); f[1][0] = 1;
MS(nxt, 63);
int top = (1 << n) - 1;
for (int sta = 0; sta <= top; ++sta)
{
for (int i = 0; i < n; ++i)if ((sta >> i & 1) && f[sta][i])
{
for (int j = 0; j < n; ++j)if ((~sta >> j & 1) && win[j][i])
{
f[sta | 1 << j][j] = 1;
gmin(nxt[sta | 1 << j][j], i);
}
}
}
for (int i = 1; i < n; ++i)
{
if (f[top][i] && win[0][i])
{
printf("1");
print(top, i);
puts("");
return;
}
}
puts("No Solution");
}
int main()
{
while (~scanf("%d", &n))
{
for (int i = 0; i < n; ++i)scanf("%s", s[i]);
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
win[i][j] = (s[i][j] == 'W' || s[j][i] == 'L');
}
}
solve();
}
return 0;
}
/*
【trick&&吐槽】
天梯賽的題目會很喜歡給trick
所以說仔細讀題真的是太重要了——
聯賽採用主客場雙循環賽制,參賽球隊兩兩之間在雙方主場各賽一場。
聯賽戰罷,結果已經塵埃落定。此時,聯賽主席突發奇想,希望從中找出一條包含所有球隊的“食物鏈”,來說明聯賽的精彩程度。
“食物鏈”爲一個1至N的排列{ T1 T2 ... TN },滿足:球隊T1戰勝過球隊T2,球隊T2戰勝過球隊T3,……,球隊T(N-1)戰勝過球隊TN,球隊TN戰勝過球隊T1。
這裏的"戰勝過"的條件非常重要。
【題意】
我們希望找一個最小字典序的哈密頓環
【分析】
哈密頓環可以按照O(2^n * n * n)的複雜度做DP。
而現在要求字典序最小。
於是顯然可以——
把第一個位置和最後一個位置都固定爲1
然後按照貪心原則,每次把一個數放在前面做DP
【時間複雜度&&優化】
O(nlogn)
*/
【2016年團體程序設計天梯賽 L3-001】【揹包 貪心】湊零錢
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1e4 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m;
int a[N];
bool f[10005][102];
int pre[10005][102];
void print(int n, int m)
{
if (pre[n][m] == 0)printf("%d\n", m - pre[n][m]);
else
{
if(pre[n][m] != m)printf("%d ", m - pre[n][m]);
print(n - 1, pre[n][m]);
}
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
for (int i = 1; i <= n; ++i)scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
reverse(a + 1, a + n + 1);
MS(f[0], 0); f[0][0] = 1;
for (int i = 1; i <= n; ++i)
{
int x = a[i];
for (int j = m; j >= 0; --j)
{
f[i][j] = f[i - 1][j];
pre[i][j] = j;
}
for (int j = m; j >= x; --j)if (f[i - 1][j - x])
{
f[i][j] = 1;
pre[i][j] = j - x;
}
}
if (!f[n][m])puts("No Solution");
else print(n, m);
}
return 0;
}
/*
【題意】
n個數中任選若干個構成和爲m
輸出字典序最小的解
【分析】
字典序最小還是從大到小向前貪心得穩妥!
*/
【2016年團體程序設計天梯賽 L3-002】【堆棧 雙SET查中位數】堆棧
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
char op[100];
multiset<int>a, b;
#include<stack>
stack<int>sta;
void update()
{
while (a.size() > b.size() + 1)
{
int val = *--a.end();
a.erase(--a.end());
b.insert(val);
}
while (a.size() < b.size())
{
int val = *b.begin();
b.erase(b.begin());
a.insert(val);
}
}
int main()
{
while(~scanf("%d", &n))
{
a.clear(); b.clear();
while (!sta.empty())sta.pop();
for (int i = 1; i <= n; ++i)
{
scanf("%s", op);
if (!strcmp(op, "Pop"))
{
if (sta.empty())puts("Invalid");
else
{
int val = sta.top(); sta.pop();
if (a.find(val) != a.end())a.erase(a.find(val));
else if (b.find(val) != b.end())b.erase(b.find(val));
update();
printf("%d\n", val);
}
}
else if (!strcmp(op, "PeekMedian"))
{
if (a.size())printf("%d\n", *--a.end());
else puts("Invalid");
}
else
{
int val; scanf("%d", &val);
sta.push(val);
if (a.empty())a.insert(val);
else if (val <= *--a.end())a.insert(val);
else b.insert(val);
update();
}
}
}
return 0;
}
/*
【trick&&吐槽】
<1> 雙set維護中位數時,插入操作是要先做判定的
<2> 如果看代碼沒找到錯,就應該思考算法邏輯的問題了
【題意】
維護棧的同時維護中位數
*/
【2016年團體程序設計天梯賽 L3-003】【並查集】社交集羣
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
int f[N], d[N];
int find(int x)
{
return f[x] == x ? x : f[x] = find(f[x]);
}
int main()
{
while(~scanf("%d", &n))
{
for (int i = 1; i <= 1000; ++i)
{
f[i] = i; d[i] = 0;
}
for (int i = 1; i <= n; ++i)
{
int g; scanf("%d%*c", &g);
if (!g)continue; --g;
int x; scanf("%d", &x);
int fa = find(x); ++d[fa];
while (g--)
{
int x; scanf("%d", &x);
x = find(x);
if (x != fa)
{
f[x] = fa; d[fa] += d[x];
}
}
}
vector<int>vt; vt.clear();
for (int i = 1; i <= 1000; ++i)if (find(i) == i && d[i])
{
vt.push_back(d[i]);
}
sort(vt.begin(), vt.end());
printf("%d\n", vt.size());
for (int i = vt.size() - 1; ~i; --i)
{
printf("%d%c", vt[i], i == 0 ? '\n' : ' ');
}
}
return 0;
}
/*
【trick&&吐槽】
理解題意非常重要。
【題意】
每個人可能有多個興趣
如果存在任意一個興趣相同,則這兩個人可以建立朋友關係
問你有多少個極大的朋友關係連通子圖
【分析】
直接並查集搞搞就好啦
注意輸出的時候是對於連通塊的根做輸出
*/
至於後面的幾道題,我們也看一下——
L3-004腫瘤診所 簡單的BFS
L3-005 垃圾箱分佈 無腦最短路
L3-006 迎風一刀斬,耐心細心分類討論
L3-007 天梯地圖 我的天,debug了一天,發現是priority_queue的運算符搞反了,於是反一反之後就得到了一個dijkstra的板子
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 505, M = N * N * 2, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m;
struct Up
{
LL c1, c2;
bool operator < (const Up &b)const
{
if (c1 != b.c1)return c1 < b.c1;
return c2 < b.c2;
}
Up operator + (const Up &b)const
{
return{ c1 + b.c1, c2 + b.c2 };
}
};
struct Node
{
int x; Up up;
bool operator < (const Node &b)const
{
return b.up < up;//Be Careful
}
};
struct Dijkstra
{
int ST, ED;
int first[N], id;
int w[M], nxt[M]; Up c[M];
Up f[N];
int pre[N];
bool sure[N];
priority_queue<Node>q;
void init()
{
for (int i = n + 1; i >= 0; --i)first[i] = 0;
id = 1;
}
void ins(int x, int y, Up up)
{
w[++id] = y;
nxt[id] = first[x];
c[id] = up;
first[x] = id;
}
void inq(int x, int y, Up up)
{
if (up < f[y])
{
f[y] = up;
pre[y] = x;
q.push({ y,f[y] });
}
}
void dijkstra(int st_, int ed_)
{
ST = st_; ED = ed_;
for (int i = n + 1; i >= 0; --i)
{
f[i] = { (LL)1e18, (LL)1e18 };
sure[i] = 0;
}
while (!q.empty())q.pop();
inq(0, ST, { 0,0 });
while (!q.empty())
{
int x = q.top().x; q.pop();
if (sure[x])continue; sure[x] = 1;
for (int z = first[x]; z; z = nxt[z])
{
inq(x, w[z], f[x] + c[z]);
}
}
}
void print(int x)
{
if (x == ST)
{
printf("%d", ST);
return;
}
print(pre[x]);
printf(" => %d", x);
}
vector<int>rd;
void getroad(int x)
{
if (x == ST)rd.clear();
else getroad(pre[x]);
rd.push_back(x);
}
}d1, d2;
int main()
{
while (~scanf("%d%d", &n, &m))
{
d1.init(); d2.init();
for (int i = 1; i <= m; ++i)
{
int x, y, oneway, len, time;
scanf("%d%d%d%d%d", &x, &y, &oneway, &len, &time);
d1.ins(x, y, { time, len });
d2.ins(x, y, { len, 1 });
if (!oneway)
{
d1.ins(y, x, { time,len });
d2.ins(y, x, { len,1 });
}
}
int st, ed; scanf("%d%d", &st, &ed);
d1.dijkstra(st, ed);
d2.dijkstra(st, ed);
d1.getroad(ed);
d2.getroad(ed);
if (d1.rd == d2.rd)
{
printf("Time = %d; ", d1.f[ed].c1);
printf("Distance = %d: ", d1.f[ed].c2);
d1.print(ed); puts("");
}
else
{
printf("Time = %d: ", d1.f[ed].c1);
d1.print(ed); puts("");
printf("Distance = %d: ", d2.f[ed].c1);
d2.print(ed); puts("");
}
}
return 0;
}
/*
【題意】
直接的多關鍵字最短路
使用dijkstra的模板寫起來更方便哦~
*/
L3-008 喊山 BFS水題
然後就沒有再做啦~~