prefix

本题是要求你找出一个组内比原字符串权值大的前缀,而一个组内包含了其他字符串的前缀,但可能也适配于这个字符串。所以说要记录这些前缀的个数才能解出这个问题。

一个方法是用std::map这样的一个红黑树字典,可以直接把string类型的前缀出现次数用int/ll类型的数字统计下来。然后再计算各前缀的权值与个数之积,逐一与原字符串权值进行比对,即可得到答案。

#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll lldcin()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
string strs[500000];
ll identify[40],ans[500000];
ll cost[500000];
map<string,ll>prefix;//记录前缀出现次数
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    ll n,m;
    cin>>n>>m;
    for(int i=1;i<=26;i++)
        cin>>identify[i];
    for(int i=1;i<=n;i++)
        cin>>strs[i];
    for(int i=1; i<=n; i++)
    {
        string tmp="";
        ll tmpr=1;
        for(int j=0; j<strs[i].size(); j++)
        {
            tmp+=strs[i][j];
            prefix[tmp]++;//录入前缀
            tmpr=(tmpr*identify[strs[i][j]-'a'+1])%m;
        }
        cost[i]=tmpr;
    }
    for(int i=1;i<=n;i++)
    {
      string tmp="";
      ll tmpcost=1;
      for(int j=0;j<strs[i].size();j++)
      {
         tmp+=strs[i][j];
         tmpcost=(tmpcost*identify[strs[i][j]-'a'+1])%m;
         if(tmpcost>cost[i])
            ans[i]+=prefix[tmp];
      }
    }
    for(int i=1;i<=n;i++)
        cout<<ans[i]<<" ";
    cout<<endl;
    return 0;
}

不过既然涉及到前缀,还有一个数据结构可满足需求,即字典树。

先来简明介绍一下字典树:字典树是一个26叉树,每一个节点对应26个子结点,也就是不同的英文字母。root,根节点不存储任何信息,它的子结点才存储信息,通过从根节点到最底下的子结点的遍历,就可以近似于遍历了一个英文单词或一个前缀。这需要一个二维数组或者一个结构体数组实现。(模板题HDU1251)

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll lldcin()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
int trie[1000030][30], sum[1000030];
ll cnt = 1;
void ins(char text[])//插入一个单词
{
    ll root = 1;
    ll lim = strlen(text);
    for (int i = 0; i < lim; i++)
    {
        ll tmp = (text[i] - 'a'+1);
        if (trie[root][tmp] == 0)//如果当前节点没有这个字母对应的子结点,那么创建
            trie[root][tmp] =++cnt;
        sum[trie[root][tmp]]++;//记录从第一个节点到现在的前缀或是单词出现的次数
        root = trie[root][tmp];//迭代搜索
    }
    return;
}
ll query(char text[])
{
    ll root = 1;
    ll lim = strlen(text);
    for (int i = 0; i < lim; i++)
    {
        ll tmp = (text[i] - 'a'+1);
        if (trie[root][tmp] == 0)//没有这样的子结点
            return 0;
        root = trie[root][tmp];
    }
    return sum[root];
}
char input[55555];
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    while (cin.getline(input,11))//未知数量但已知长度的C++式输入,C可用GETS
    {
        if (input[0] == NULL||strlen(input)==0)
            break;
        else
            ins(input);
    }
    while (cin >> input)
        cout << query(input) << endl;
    return 0;
}

而我们恰好可以使用字典树的记录前缀数量的功能来解决这个问题,那么它的查询也就对应着前缀出现的个数。仍然是一番计算就可以解决问题。

#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll lldcin()
{
	ll tmp = 0, si = 1;
	char c;
	c = getchar();
	while (c > '9' || c < '0')
	{
		if (c == '-')
			si = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		tmp = tmp * 10 + c - '0';
		c = getchar();
	}
	return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
int trie[125000][30], ans[125000],cost[925000],sum[125000],totalcost[125000];
int identify[30];
string strs[125000];
ll cnt = 2;
void ins(string info,int mod)
{
	ll root = 1;
	for (int i = 0; info[i]; i++)
	{
		ll next = (info[i] - 'a' + 1);
		if (trie[root][next] == 0)
			trie[root][next] = cnt++;
		sum[trie[root][next]]++;
		//ll current = cnt - 1;
		//if (cnt == 2)
		//	cost[trie[root][next]] = identify[next] % mod;
		//else
		//	cost[trie[root][next]] = (cost[trie[current][next]] * identify[next]) % mod;
		root = trie[root][next];
	}
	return;
}
int query(string info,int mod,int index)//查询前缀出现次数
{
	ll root = 1;
	for (int i = 0; info[i]; i++)
	{
		ll next = (info[i] - 'a' + 1);
		if (trie[root][next] == 0)
			return 0;
		root = trie[root][next];
	}
	//if(info.size()==strs[index].size())
	//	cout << cost [root]<< endl;
	//if (cost[root]> totalcost[index])
		return sum[root];
	//else
	//	return 0;
}
int DETERMINATION()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= 924009; i++)
		cost[i] = 1;
	for (int i = 1; i <= 26; i++)
		cin >> identify[i];
	for (int i = 1; i <= n; i++)
	{
		cin >> strs[i];
		ins(strs[i],m);
		ll tmp = 1;
		for (int j = 0;strs[i][j]; j++)
		{
			tmp = (tmp*identify[strs[i][j] - 'a' + 1]) % m;
		}
		totalcost[i] = tmp;//计算原字符串权值
	}
	//for (int i = 1; i <= n; i++)
	//	cout << "Total:" << totalcost[i] << endl;
	for (int i = 1; i <= n; i++)
	{
		string tmp = "";
		ll tmpvalue = 1;
		for (int j = 0;j<strs[i].size()-1; j++)
		{
			tmp += strs[i][j];
			tmpvalue = (tmpvalue*identify[strs[i][j] - 'a' + 1]) % m;
			if(tmpvalue>totalcost[i])
				ans[i] += query(tmp, m, i);//计算
		}
	}
	for (int i = 1; i <= n; i++)
		cout << ans[i] <<" ";
	return 0;
}

 

posted @ 2019-07-28 23:36  完全墨染的樱花  阅读(488)  评论(0)    收藏  举报