#include<iostream>
#include<algorithm>
#include<functional>
#include<map>
#include <string>
#include<iomanip>
#include<cstdio>
#include<math.h>
#include<stack>
#include<queue>
#include<cstring>
#include<vector>
#define FOR(i,a,b) for(ll i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)
#define EREP(i,n) for(int i=(n-1);i>=0;--i)
#define D(n,retu) REP(i,n){cin>>retu[i];}
#define mod 1000000007
#define MIN -93193111451418101
#define INF 931931114518101
using namespace std;
typedef long long int ll;
template<typename T>
void fill_all(T& arr, const T& v) {
	arr = v;
}
template<typename T, typename ARR>
void fill_all(ARR& arr, const T& v) {
	for (auto& i : arr) { fill_all(i, v); }
}
#define MAX_NUM 50
long long comb[MAX_NUM + 1][MAX_NUM + 1];

ll par[100000], depth[100000];
static void calc_comb()
{
	for (uint32_t i = 0; i <= MAX_NUM; i++) {
		for (uint32_t j = 0; j <= i; j++) {
			if ((j == 0) || (i == j)) {
				comb[i][j] = 1;
			}
			else {
				comb[i][j] = comb[i - 1][j - 1] + comb[i - 1][j];
			}
		}
	}
}


void init(ll n) {
	REP(i, n) {
		par[i] = i;
		depth[i] = 0;
	}
	return;
}

ll find(ll x) {
	if (par[x] == x) { return x; }
	else { return par[x] = find(par[x]); }
}

void merge(ll x, ll y) {
	x = find(x); y = find(y);
	if (x == y) { return; }
	if (depth[x] > depth[y]) {
		par[y] = x;
	}
	else {
		par[x] = y;
		if (depth[x] == depth[y]) {
			depth[y]++;
		}
	}
}

bool same(ll x, ll y) {
	if (find(x) == find(y)) {
		return false;
	}
	return true;
}
int lcs(string X, string Y) {
	const int N = max(X.size(), Y.size()) + 1;
	vector<vector<int> > c(N, vector<int>(N, 0));
	int m = X.size();
	int n = Y.size();
	int maxl = 0;
	X = ' ' + X;
	Y = ' ' + Y;
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			if (X[i] == Y[j]) c[i][j] = c[i - 1][j - 1] + 1;
			else c[i][j] = max(c[i - 1][j], c[i][j - 1]);
			maxl = max(maxl, c[i][j]);
		}
	}
	return maxl;
}
struct Node {
	map<char, int> next;    // nodeの両端にcharをつけたときにいくnodeのindex
	int len = 0;            // 回文の長さ
	int sufflink = 0;       // nodeのsuffix palindromeであるnodeのindex
	int num = 0;
};

class PalindromicTree {
public:
	string str;
	vector<Node> tree;
	int last_node_idx;                  // 一番最後にできたnodeのidx
	int max_suffix_palindrome_idx;      // 現在の最長の接尾辞回文のnodeのidx

	PalindromicTree(string s) : str(s) {
		this->tree.resize(s.size() + 2);
		this->last_node_idx = 1;
		this->max_suffix_palindrome_idx = 1;

		this->tree[0].len = -1;
		this->tree[0].sufflink = 0;
		this->tree[1].len = 0;
		this->tree[1].sufflink = 0;
	}

	bool addLetter(int pos) {

		char now_char = this->str[pos];

		// suffix linkをたどり，xAxを見つける
		int A = max_suffix_palindrome_idx;    // 現在着目してるnodeのidx
		while (true) {
			int curlen = tree[A].len; // Aの長さ
			if (pos - 1 - curlen >= 0 && this->str[pos - 1 - curlen] == now_char) {
				break;
			}
			A = tree[A].sufflink;
		}

		// すでにnodeがある
		if (this->tree[A].next[now_char] != 0) {
			max_suffix_palindrome_idx = tree[A].next[now_char];
			return false;
		}

		// ノードを追加
		max_suffix_palindrome_idx = ++this->last_node_idx;
		Node &new_node = tree[this->last_node_idx];
		new_node.len = tree[A].len + 2;
		tree[A].next[now_char] = this->last_node_idx;   // AからxAxにedgeを張る

														// 長さが1の回文のsuffix linkは固定
		if (new_node.len == 1) {
			new_node.sufflink = 1; // 1文字のnodeのsuffix link先は空文字のnode
			new_node.num = 1;
			return true;
		}

		// さらにsuffix linkをたどり，xBxを見つける
		int B = A;
		while (true) {
			B = tree[B].sufflink;
			int curlen = tree[B].len; // Bの長さ
			if (pos - 1 - curlen >= 0 && this->str[pos - 1 - curlen] == now_char) {
				break;
			}
		}

		new_node.sufflink = tree[B].next[now_char];   // xAxからxBxへsufifixを張る
		new_node.num = 1 + tree[new_node.sufflink].num;

		return true;
	}
};

/*
sに含まれる回文ののべ数をもとめる
aaaならaが3個，aaが2個，aaaが1個で合計6個の回文が含まれる
*/
ll num_of_palindrome(string s) {
	PalindromicTree pt(s);
	ll ans = 0;
	for (int i = 0; i < s.size(); i++) {
		pt.addLetter(i);
		ans += pt.tree[pt.max_suffix_palindrome_idx].num;
	}
	return ans;
}
//------------------変数-----------------------//
ll abc[50] = {};
//-------------------関数----------------------//

int main() {
	string s; cin >> s;
	REP(i, s.size()) {
		abc[(int)s[i] - (int)'a']++;
	}
	ll si = s.size();
	ll cnt = 0;
	REP(i, si) { cnt += i; }

	REP(i, 50) {
		if (abc[i] >1) {
			cnt -= abc[i] * (abc[i] - 1) / 2;
		}
	}
	cout << cnt +1<< endl;
}

Measured memory_bytes: 640