哎呀~
今年初赛做得太仓促,又犯蠢卡题了,做得不好。
所以现在决定临时训练一下!
下面是今年大区赛的题目信息——
前面什么排序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水题
然后就没有再做啦~~