Problem:
Problem F:
Two-finger Programming
Franklin Jenkins is a programmer, but he isn’t good at typing keyboards. So he always uses only ‘f’
and ‘j’ (keys on the home positions of index fingers) for variable names. He insists two characters are
enough to write programs, but naturally his friends don’t agree with him: they say it makes programs too
long.
He asked you to show any program can be converted into not so long one with the
f-j names
. Your task
is to answer the shortest length of the program after all variables are renamed into the f-j names, for each
given program.
Given programs are written in the language specified below.
A block (a region enclosed by curly braces: ‘{’ and ‘}’) forms a scope for variables. Each scope can have
zero or more scopes inside. The whole program also forms the global scope, which contains all scopes
on the top level (i.e., out of any blocks).
Each variable belongs to the innermost scope which includes its declaration, and is valid from the decla-
ration to the end of the scope. Variables are never redeclared while they are valid, but may be declared
again once they have become invalid. The variables that belong to different scopes are regarded as differ-
ent even if they have the same name. Undeclared or other invalid names never appear in expressions.
The tokens are defined by the rules shown below. All whitespace characters (spaces, tabs, linefeeds, and
carrige-returns) before, between, and after tokens are ignored.
token
:
identifier
|
keyword
|
number
|
operator
|
punctuation
identifier
:
     [a-z]+ (one or more lowercase letters)
keyword
:
     [A-Z]+ (one or more uppercase letters)
number
:
     [0-9]+ (one or more digits)
operator
:
     ‘=’ | ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘&’ | ‘|’ | ‘^’ | ‘<’ | ‘>’
punctuation
:
     ‘{’ | ‘}’ | ‘(’ | ‘)’ | ‘;’
The syntax of the language is defined as follows.
program
:
statement-list
statement-list
:
statement
statement-list statement
statement
:
variable-declaration
if-statement
while-statement
expression-statement
block-statement
variable-declaration
:
      “VAR”
identifier
‘;’
if-statement
:
      “IF” ‘(’
expression
‘)’
block-statement
while-statement
:
      “WHILE” ‘(’
expression
‘)’
block-statement
expression-statement
:
expression
‘;’
block-statement
:
      ‘{’
statement-listoptional
‘}’
expression
:
identifier
number
expression operator expression
Input
The input consists of multiple data sets.
Each data set gives a well-formed program according to the specification above. The first line contains
a positive integer
N
, which indicates the number of lines in the program. The following
N
lines contain
the program body.
There are no extra characters between two adjacent data sets.
A single line containing a zero indicates the end of the input, and you must not process this line as part
of any data set.
Each line contains up to 255 characters, and all variable names are equal to or less than 16 characters
long. No program contains more than 1000 variables nor 100 scopes 
...(truncated)

Submitted solutions:

code_snippet: // AOJ #2098 Two-finger Programming
// 2025.4.30

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct Var { int scope, start, end; ll w; };
enum TokType { ID, KW, NUM, OP, PUNC };

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    while (true) {
        int N;
        cin >> N;
        if (N == 0) break;
        string line, prog;
        getline(cin, line);
        for (int i = 0; i < N; i++) {
            getline(cin, line);
            prog += line;
            prog += '\n';
        }

        vector<pair<TokType,string>> tokens;
        tokens.reserve(prog.size()/2);

        vector<vector<int>> vars_in_scope;
        vars_in_scope.emplace_back();

        vector<int> scope_stack = {0};
        int next_scope_id = 1;

        unordered_map<string, vector<int>> name_stack;
        vector<Var> varinfos;
        bool expect_decl = false;

        int pos = 0, L = prog.size();
        int tok_idx = 0;
        while (pos < L) {
            char c = prog[pos];
            if (isspace(c)) { pos++; continue; }

            if (islower(c)) {
                int p = pos;
                while (p < L && islower(prog[p])) p++;
                string s = prog.substr(pos, p-pos);
                tokens.emplace_back(ID, s);
                if (expect_decl) {
                    int vid = varinfos.size();
                    varinfos.push_back({ scope_stack.back(), tok_idx, -1, 1 });
                    name_stack[s].push_back(vid);
                    if ((int)vars_in_scope.size() <= scope_stack.back())
                        vars_in_scope.resize(scope_stack.back()+1);
                    vars_in_scope[scope_stack.back()].push_back(vid);
                    expect_decl = false;
                } else {
                    auto &stk = name_stack[s];
                    int vid = stk.back();
                    varinfos[vid].w++;
                }
                pos = p;
                tok_idx++;
            } else if (isupper(c)) {
                int p = pos;
                while (p < L && isupper(prog[p])) p++;
                string s = prog.substr(pos, p-pos);
                tokens.emplace_back(KW, s);
                expect_decl = (s == "VAR");
                pos = p;
                tok_idx++;
            } else if (isdigit(c)) {
                int p = pos;
                while (p < L && isdigit(prog[p])) p++;
                string s = prog.substr(pos, p-pos);
                tokens.emplace_back(NUM, s);
                expect_decl = false;
                pos = p;
                tok_idx++;
            } else {
                string s(1, c);
                TokType tp = OP;
                if (string("{}();").find(c) != string::npos) tp = PUNC;
                tokens.emplace_back(tp, s);
                expect_decl = false;
                if (c == '{') {
                    int sc = next_scope_id++;
                    scope_stack.push_back(sc);
                    vars_in_scope.emplace_back();
                } else if (c == '}') {
                    int sc = scope_stack.back();
                    for (int vid : vars_in_scope[sc]) {
                        varinfos[vid].end = tok_idx;
                    }
                    scope_stack.pop_back();
                }
                pos++;
                tok_idx++;
            }
        }
        int Ttok = tok_idx;
        for (int vid : vars_in_scope[0]) varinfos[vid].end = Ttok;

        int M = varinfos.size();
        vector<string> pool;
        pool.reserve(M);
        for (int len = 1; (int)pool.size() < M; len++) {
            int limit = 1 << len;
            for (int m = 0; m < limit && (int)pool.size() < M; m++) {
                string s(len, 'f');
                for (int b = 0; b < len; b++) if ((m >> (len-1-b)) & 1) s[b] = 'j';
                pool.push_back(s);
            }
        }

        vector<bool> alive(M, true);
        vector<int> color_of(M, -1);
        int color_idx = 0;

        while (true) {
            vector<int> rem;
            rem.reserve(M);
            for (int i = 0; i < M; i++) if (alive[i]) rem.push_back(i);
            if (rem.empty()) break;

            int n = rem.size();
            struct I { int end, start, id; ll w; };
            vector<I> iv(n);
            for (int i = 0; i < n; i++) {
                iv[i] = { varinfos[rem[i]].end,
                          varinfos[rem[i]].start,
                          rem[i],
                          varinfos[rem[i]].w };
            }
            sort(iv.begin(), iv.end(),
                 [](auto &a, auto &b){
                   if (a.end != b.end) return a.end < b.end;
                   return a.start < b.start;
                 });

            vector<int> p(n);
            vector<ll> dp(n+1, 0);

            for (int i = 0; i < n; i++) {
                int lo = 0, hi = i-1, best = -1;
                while (lo <= hi) {
                    int mid = (lo+hi)/2;
                    if (iv[mid].end < iv[i].start) {
                        best = mid;
                        lo = mid+1;
                    } else hi = mid-1;
                }
                p[i] = best;
            }

            dp[0] = 0;
            for (int i = 1; i <= n; i++) {
                ll take = iv[i-1].w + (p[i-1] >= 0 ? dp[p[i-1]+1] : 0);
                dp[i] = max(dp[i-1], take);
            }

            vector<bool> pick(n, false);
            int i = n;
            while (i > 0) {
                ll take = iv[i-1].w + (p[i-1] >= 0 ? dp[p[i-1]+1] : 0);
                if (take >= dp[i-1]) {
                    pick[i-1] = true;
                    i = p[i-1] + 1;
                } else i--;
            }

            for (int k = 0; k < n; k++) {
                if (pick[k]) {
                    int vid = iv[k].id;
                    color_of[vid] = color_idx;
                    alive[vid] = false;
                }
            }
            color_idx++;
        }

        ll other = 0;
        for (auto &tk : tokens) {
            if (tk.first == ID) continue;
            if (tk.first == KW || tk.first == NUM) other += tk.second.size();
            else other += 1;
        }
        ll rename_cost = 0;
        for (int i = 0; i < M; i++) {
            int ci = color_of[i];
            rename_cost += varinfos[i].w * (int)pool[ci].size();
        }
        cout << (other + rename_cost) << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 5012
final_rank: 1

code_snippet: #include <iostream>
#include <string>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cctype>
#include <map>
#include <functional>
using namespace std;

typedef vector<int> vint;

int ans;
const char *ptr;
char buf[256];
map<string,int> mp;

size_t cmp(const vint &v1, const vint &v2){
	return v1.size() < v2.size();
}

vint block(bool brace, string defvar = string()){
	vector<vint> freqs;
	map<string,int>::iterator it;
	
	if(!defvar.empty()){
		mp.insert(make_pair(defvar, 1));
	}

	if(brace) ++ptr;
	while(*ptr != '}'){
		if(*ptr == '{'){
			freqs.push_back(block(true));
		}
		else if(*ptr == 'V'){	//VAR
			ptr += 3;
			ans += 3;

			int dif = 0;
			sscanf(ptr, " %[a-z]%n", buf, &dif);
			string varname = buf;
			ptr += dif;

			freqs.push_back(block(false, varname));
		}
		else if(islower(*ptr)){
			sscanf(ptr, "%[a-z]", buf);
			string varname = buf;
			ptr += varname.size();
			++mp[varname];
		}
		else if(!isspace(*ptr++)){
			++ans;
		}
	}
	if(brace){
		++ptr;
		ans += 2;
	}

	vint res;
	if(freqs.size() == 1){
		res.swap(freqs[0]);
	}
	else if(freqs.size() > 1){
		int maxsize = max_element(freqs.begin(), freqs.end(), cmp)->size();
		for(int i = 0; i < maxsize; ++i){
			int s = 0;
			for(int j = 0; j < freqs.size(); ++j){
				if(i < freqs[j].size()){
					s += freqs[j][i];
				}
			}
			res.push_back(s);
		}
	}

	if(!defvar.empty()){
		map<string,int>::iterator it = mp.find(defvar);
		res.push_back(it->second);
		mp.erase(it);
	}
	sort(res.begin(), res.end(), greater<int>());

	return res;
}

int main(){
	string s, lines;
	int n;
	while(cin >> n, n){
		cin.ignore();
		lines = "{";
		for(int i = 0; i < n; ++i){
			getline(cin, s);
			lines += s;
		}
		lines += '}';
		
		ans = -2;
		mp.clear();
		ptr = lines.c_str();
		vint v = block(true);
		
		v.resize(1024, 0);
		vint::iterator it1 = v.begin(), it2;
		for(int i = 1; i <= 9; ++i){
			it2 = it1 + (1 << i);
			ans += accumulate(it1, it2, 0) * i;
			it1 = it2;
		}
		
		cout << ans << '\n';
	}
}
accuracy: 1
time_ms: 320
memory_kb: 1808
final_rank: 1

code_snippet: #include <iostream>
#include <string>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cctype>
#include <map>
#include <functional>
using namespace std;

typedef vector<int> vint;

int ans;
const char *ptr;
char buf[256];
map<string,int> mp;

size_t cmp(const vint &v1, const vint &v2){
	return v1.size() < v2.size();
}

vint block(bool brace, string varname = string()){
	vector<vint> freqs;
	map<string,int>::iterator it;
	
	vector<string> varlist;
	if(!varname.empty()){
		varlist.push_back(varname);
		mp.insert(make_pair(varname, 1));
	}

	if(brace) ++ptr;
	while(*ptr != '}'){
		if(*ptr == '{'){
			freqs.push_back(block(true));
		}
		else if(*ptr == 'V'){	//VAR
			ptr += 3;
			ans += 3;

			int dif = 0;
			sscanf(ptr, " %[a-z]%n", buf, &dif);
			varname = buf;
			ptr += dif;

			freqs.push_back(block(false, varname));
		}
		else if(islower(*ptr)){
			sscanf(ptr, "%[a-z]", buf);
			varname = buf;
			ptr += varname.size();
			++mp[varname];
		}
		else if(!isspace(*ptr++)){
			++ans;
		}
	}
	if(brace){
		++ptr;
		ans += 2;
	}

	vint res;
	if(freqs.size() == 1){
		res.swap(freqs[0]);
	}
	else if(freqs.size() > 1){
		int maxsize = max_element(freqs.begin(), freqs.end(), cmp)->size();
		for(int i = 0; i < maxsize; ++i){
			int s = 0;
			for(int j = 0; j < freqs.size(); ++j){
				if(i < freqs[j].size()){
					s += freqs[j][i];
				}
			}
			res.push_back(s);
		}
	}

	for(int i = 0; i < varlist.size(); ++i){
		it = mp.find(varlist[i]);
		res.push_back(it->second);
		mp.erase(it);
	}
	sort(res.begin(), res.end(), greater<int>());

	return res;
}

int main(){
	string s, lines;
	int n;
	while(cin >> n, n){
		cin.ignore();
		lines = "{";
		for(int i = 0; i < n; ++i){
			getline(cin, s);
			lines += s;
		}
		lines += '}';
		
		ans = -2;
		mp.clear();
		ptr = lines.c_str();
		vint v = block(true);
		
		v.resize(1024, 0);
		vint::iterator it1 = v.begin(), it2;
		for(int i = 1; i <= 9; ++i){
			it2 = it1 + (1 << i);
			ans += accumulate(it1, it2, 0) * i;
			it1 = it2;
		}
		
		cout << ans << '\n';
	}
}
accuracy: 1
time_ms: 320
memory_kb: 1824
final_rank: 3