Description
Frederick is a young programmer. He participates in all programming contests he can find and always uses his favorite programming language Fygon. Unfortunately, he often receives Time Limit Exceeded outcome, even when his algorithm is asymptotically optimal. That’s because the Fygon interpreter is very slow. Nevertheless, Frederick likes Fygon so much, that he uses non-asymptotical optimizations to fit the solution into time limit. To make it easier, he asks you to write a program, which will be able to estimate the exact number of operations that his Fygon program makes.
For simplicity, we will assume that Fygon has only two statements. The first statement is lag. It substitutes almost any other statement. The second statement is a for loop:
for < variable > in range (< limit >):
< body >
This means that < variable > iterates over values from 0 to < limit >−1. In Fygon < variable > is a lowercase letter from
a
to
The program receives the input in the variable
n
. This variable has special meaning and cannot be used as a loop variable.
Your task is to find the formula that calculates the number of performed lag operations by the given Fygon program, depending on the value of the variable
Input
The input file contains the Fygon program. No two loops use the same variable as iterators. Each variable used inside a range is either
n
or declared in some outer loop.
The program has at most
Output
Output the formula for the number of performed lag operations depending on
⟨Expression⟩ ::= ⟨Product⟩ ( (‘+’ | ‘-’) ⟨Product⟩)
⟨Product⟩ ::= ⟨Value⟩ (‘*’⟨Value⟩)
⟨Value⟩ ::= ‘n’ | ⟨Number⟩ | ‘-’⟨Value⟩ | ‘(’⟨Expression⟩‘)’
⟨Number⟩ ::= [‘0’..‘9’] +(‘/’ [‘0’..‘9’] +)?
Sample Input
for i in range(n):
for j in range(i):
lag
for x in range(5):
for y in range(n):
for z in range(n):
lag
lag
Sample Output
1/2 * n * (n-1) + 5 * (n*n + 1)
Hint & Source
Time limit: 2 seconds
Memory limit: 256 megabytes
ACM ICPC 2015-2016, NEERC, Northern Subregional Contest
Solution & Code
可以看出要求的表达式是一个关于
n
的多项式,即
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
int ans, res[7], tot, lst[105];
int var_val[26], oper[105], now_var[105], to_var[105], numb[105];
bool is_numb[105];
char str[105];
vector<int> son[105];
void dfs(int u){
if(oper[u] == 0) return;
if(oper[u] == 2) ++ans;
if(oper[u] == 1){
if(is_numb[u]){
for(var_val[now_var[u]] = 0; var_val[now_var[u]] < numb[u]; ++var_val[now_var[u]])
for(int l = 0; l < son[u].size(); ++l) dfs(son[u][l]);
} else{
for(var_val[now_var[u]] = 0; var_val[now_var[u]] < var_val[to_var[u]]; ++var_val[now_var[u]])
for(int l = 0; l < son[u].size(); ++l) dfs(son[u][l]);
}
}
}
void calc(int n){
ans = 0;
var_val['n'-'a'] = n;
for(int l = 0; l < son[0].size(); ++l) dfs(son[0][l]);
res[n] = ans;
}
typedef long long ll;
struct frac{
ll a, b;
frac(ll a = 1, ll b = 1) : a(a), b(b) {}
void reduce(){
if(a == 0){
b = 1;
return;
} else{
ll g = std::__gcd(std::abs(a), std::abs(b));
a /= g, b /= g;
if(a < 0 && b < 0) a = -a, b = -b;
else if(b < 0) a = -a, b = -b;
}
}
frac friend operator * (frac x, frac y){
frac rtn = frac(x.a * y.a, x.b * y.b);
rtn.reduce();
return rtn;
}
frac friend operator / (frac x, frac y){
frac rtn = frac(x.a * y.b, x.b * y.a);
rtn.reduce();
return rtn;
}
frac friend operator + (frac x, frac y){
frac rtn = frac(x.a * y.b + y.a * x.b, x.b * y.b);
rtn.reduce();
return rtn;
}
frac friend operator - (frac x, frac y){
frac rtn = frac(x.a * y.b - y.a * x.b, x.b * y.b);
rtn.reduce();
return rtn;
}
};
frac a[7][8];
int main(){
// 读入以及给n赋值,并构造出高斯消元矩阵
while(gets(str)){
++tot;
int l = strlen(str), p = 0;
while(str[p] == ' ') ++p;
son[lst[p/4]].push_back(tot);
lst[p/4+1] = tot;
if(str[p] == 'l'){
oper[tot] = 2;
continue;
} else{
oper[tot] = 1;
while(str[p] != ' ') ++p; ++p;
now_var[tot] = str[p] - 'a';
while(str[p] != '(') ++p; ++p;
if(str[p] >= '0' && str[p] <= '9') is_numb[tot] = true, numb[tot] = str[p] - '0';
else to_var[tot] = str[p] - 'a';
}
}
for(int i = 0; i <= 6; ++i) calc(i);
for(int i = 0; i <= 6; ++i) a[i][7] = frac(res[i], 1);
for(int i = 0; i <= 6; ++i){
a[i][0] = frac(1, 1);
for(int j = 1; j <= 6; ++j) a[i][j] = frac(a[i][j-1].a * i, 1);
}
// 高斯消元
for(int i = 0; i <= 6; ++i){
int tmp = -1;
for(int j = i; j <= 6; ++j) if(tmp == -1 && a[j][i].a != 0) tmp = j;
for(int j = 0; j <= 7; ++j) swap(a[i][j], a[tmp][j]);
for(int j = i + 1; j <= 6; ++j){
frac t = a[j][i] / a[i][i];
for(int k = 0; k <= 7; ++k) a[j][k] = a[j][k] - (a[i][k] * t);
}
}
for(int i = 6; i >= 0; --i){
for(int j = i + 1; j <= 6; ++j) a[i][7] = a[i][7] - a[i][j] * a[j][7];
a[i][7] = a[i][7] / a[i][i];
}
// 输出答案
bool first = true;
for(int i = 0; i <= 6; ++i){
if(a[i][7].a == 0) continue;
if(!first) printf(" + ");
first = false;
for(int j = 1; j <= i; ++j) printf("n * ");
printf("%I64d/%I64d", a[i][7].a, a[i][7].b);
}
return 0;
}