题解:UVA126 The Errant Physicist
b__b
·
·
题解
~太好了是大模拟我们没救了~
此题难点在于输入与输出,~以及克服奇怪的题面和奇怪的翻译~。
题面简述
有若干个测试数据,每一个测试数据有两个行,分别代表两个多项式,将这两个多项式相乘。输入格式已比较透彻,只需注意 x 与 y 的输入顺序可能调换。
每一个测试数据输出两行,第一行为指数行,下一行为底数行。
第一行包含所有指数,相对于其余行适当定位信息。
实现
可以先将第一行的多项式输入完成,接着~由人教版八年级上册数学书~可得
一般的,单项式与多项式相乘,就是用单项式去乘多项式的每一项,再把所得的积相加。
一般的,多项式与多项式相乘,先用一个多项式的每一项乘另一个多项式的每一项,再把所得的积相加。
因此我们只需要在第二行不断输入单项式,遍历原多项式的每一项单项式相乘后放入结果。
需要进行指数的判重,可以用 map 实现,找到指数相同的单项式后将系数相加,因为 ax^m+bx^m=(a+b)x^m(其中 a,b 均为常整数),合并后可能会出现系数为 0 的情况,输出时要把这些系数为 0 的单项式忽略。
输出行中的项必须按 x 的幂次降序排列,对于给定的幂次按照 y 的幂次递增的顺序。
例如,对于 4y^{17}-1-x^5,
- 由于 -x^5 是这个多项式内 x 的次数最高的单项式,因此将 -x^5 放到最前面。
- 因为 -1 可看作 -y^0,因此这是这个多项式内 y 的次数最低的单项式,因此将 -1 放到第二个。
- 将 4y^{17} 放到最后。
综上所述,这个多项式的排序结果为 -x^5-1+4y^{17}。
写成 C++ 代码可表示为:(xcs 为 x 的次数,ycs 为 y 的次数)
if (a.xcs > b.xcs) return 1;
else if (a.xcs < b.xcs) return 0;
else return a.ycs < b.ycs;
第一行包含所有指数,相对于其余行适当定位信息。
个人感觉是本题最难的地方,理解和实现都有点困难(再加上奇怪的输出样例就更难了)。
下文中 \mathrm{ans1} 为第一行的输出的缓冲,\mathrm{ans2} 为第二行的输出的缓冲,\mathrm{ansind} 为输出的字符数量,直接说输出时指输出到 \mathrm{ans2}。
用上文已排序的 -x^5-1+4y^{17} 举例,
- 先输出 -x^5,
如果第一项的系数为负,则在第一列中以一元减号开头,中间没有空白栏。
$\qquad$将 $-x$ 输出,完成后 $\mathrm{ansind}=2$。
$\qquad$开始输出指数 $5$,因为此时 $\mathrm{ansind}=2$,所以将 $5$ 放进 $\mathrm{ans1}$ 的第 $3$ 个字符,完成后 $\mathrm{ansind}=3$。
3. 开始输出 $-1$,
> 二进制正负(即输出中连接项的正负)前后都有一个空白列。
$\qquad$因此实际上要输出的为 $\;-\;1$(前后都有一个空格),输出后 $\mathrm{ansind}=7$。
4. 开始输出 $+4y^{17}$,同上文,实际上要输出的为 $\;+\;4y^{17}$,将 $\;+\;$ 输出后 $\mathrm{ansind}=10$,还剩下 $4y^{17}$ 需要输出。
开始输出 $4y$,输出后 $\mathrm{ansind}=12$。
接着输出指数 $17$,将 $17$ 放入 $\mathrm{ans1}$ 的第 $12$ 个字符,输出后 $\mathrm{ansind}=14$。
输出完成,$\mathrm{ans1}$ 的内容为:``` 5 17```,
$\mathrm{ans2}$ 的内容为:```-x - 1 + 4y ```
($\mathrm{ans2}$ 后面有两个空格的原因是因为题目要求上下两行输出长度相同,使用空格填充)。
## 代码
```cpp
//喜欢我的抽象马蜂吗
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <map>
struct dan {
int xs, xcs, ycs;
} oldduo[100], newduo[100];
char s[100], ans1[100], ans2[100];
int oldduoind, i, newduoind, ansind;
std::map<int, std::map<int, int>> pc;
int readd() { //这一个每次都会将i设为在当前的i后面的第一个非数字字符
int ans = 0;
for (; isdigit(s[i]); ++i) ans = ans * 10 + s[i] - '0';
return ans;
}
void readdan(dan &dan) { //由于使用了上面的readd,因此会有readd的特性
dan.xs = 1, dan.xcs = dan.ycs = 0;
if (s[i] == '-') {
if (isdigit(s[++i])) dan.xs = -readd();
else dan.xs = -1;
} else {
if (s[i] == '+') ++i;
if (isdigit(s[i])) dan.xs = readd();
}
while (isalpha(s[i])) if (s[i] == 'x') {
if (isdigit(s[++i])) dan.xcs = readd();
else dan.xcs = 1;
} else if (s[i] == 'y') {
if (isdigit(s[++i])) dan.ycs = readd();
else dan.ycs = 1;
}
}
void qc(int &ind, dan *duo) { //判重,如果有相同的项就合并
auto it = pc.find(duo[ind].xcs);
if (it == pc.end()) pc[duo[ind].xcs][duo[ind].ycs] = ind, ++ind;
else {
auto nit = it->second.find(duo[ind].ycs);
if (nit == it->second.end()) it->second[duo[ind].ycs] = ind, ++ind;
else duo[nit->second].xs += duo[ind].xs;
}
}
void scdannofu(dan &dan) { //输出一个单项式,这个单项式的项数已去除符号
if (dan.xs != 1) ans2[ansind += sprintf(ans2 + ansind, "%d", dan.xs)] = ' ';
else {
if (!dan.xcs && !dan.ycs) {
ans2[ansind++] = '1', ++ansind;
return;
}
}
if (dan.xcs) {
ans2[ansind++] = 'x';
if (dan.xcs > 1) ans1[ansind += sprintf(ans1 + ansind, "%d", dan.xcs)] = ' ';
}
if (dan.ycs) {
ans2[ansind++] = 'y';
if (dan.ycs > 1) ans1[ansind += sprintf(ans1 + ansind, "%d", dan.ycs)] = ' ';
}
++ansind; //往后面放入一个空格
}
int main() {
for (;;) {
fgets(s, 100, stdin);
if (s[0] == '#') break;
for (i = oldduoind = newduoind = ansind = 0, pc.clear(); s[i] != '\n';) readdan(oldduo[oldduoind]), qc(oldduoind, oldduo);
for (i = 0, pc.clear(), fgets(s, 100, stdin); s[i] != '\n';) {
dan p;
readdan(p);
for (int j = 0; j < oldduoind; ++j) {
dan &now = newduo[newduoind], &bef = oldduo[j];
now.xs = p.xs * bef.xs, now.xcs = p.xcs + bef.xcs, now.ycs = p.ycs + bef.ycs, qc(newduoind, newduo);
}
}
for (i = 0, std::sort(newduo, newduo + newduoind, [] (const dan &a, const dan &b) -> bool {
if (a.xcs > b.xcs) return 1;
else if (a.xcs < b.xcs) return 0;
else return a.ycs < b.ycs;
}); i < 100; ++i) ans1[i] = ans2[i] = ' '; //填充空格
for (i = 0; !newduo[i].xs; ++i);
if (newduo[i].xs < 0) ans2[0] = '-', ansind = 1, newduo[i].xs = -newduo[i].xs;
for (scdannofu(newduo[i++]); i < newduoind; ++i) {
if (newduo[i].xs < 0) ans2[ansind++] = '-', newduo[i].xs = -newduo[i].xs;
else if (newduo[i].xs > 0) ans2[ansind++] = '+';
else continue;
++ansind, scdannofu(newduo[i]);
}
ans1[ansind - 1] = ans2[ansind - 1] = 0, printf("%s\n%s\n", ans1, ans2);
}
}
```