Fygon

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 z, and < limit > is either already defined < variable > or a positive integer constant. The < body > of the loop is indented by four spaces and contains at least one statement.
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 n.

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 20 statements and at most 6 of them are loops. All integer constants are from 1 to 9 .

Output

Output the formula for the number of performed lag operations depending on n. The length of the formula should be at most 100 characters (excluding spaces). The formula should correspond to the following grammar:

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 的多项式,即 Σ6i=0xini,故求出7个系数即可,可以分别给 n <script type="math/tex" id="MathJax-Element-293">n</script> 赋7个值,然后模拟出多项式的结果,建立7个方程,然后高斯消元。

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值