目录
A:Browser Games(字符串哈希)
题意:
给出n个字符串,你需要输出n行。
对于第i个字符串来说,你需要在1~i这些字符串找到一些最小的前缀数量,并且这些前缀都属于1~i这些字符串的某些前缀,但不能属于在i+1~n字符串的前缀。
solution:
正着想很难实现,所以要倒着想(正难则反)
对于所有1~n的字符串,答案就是不同首字母的个数。
我们把n个字符串的前缀都hash出来,并且把前缀的下标也存起来,比如前n字符串的下标都为0,倒着求答案,接下来把当前字符串的相同前缀的前面的字符串都找出来(用map用hash值做映射,把相同前缀的字符串id存进去),把前面与当前字符串前缀相同的字符串下标位置+1,然后把旧的前缀map删掉更新,当前map的size()就是答案,这样贪心的求一定是最优解。
一路往前递推就完成任务了。
(字典树似乎也能写,但是我不会)
#include <bits/stdc++.h>
// #define int long long
#define ull unsigned long long
using namespace std;
unordered_map<ull,vector<int>>mp;
const int P=13331;
const int N=1e5+10;
ull hs[N]; //第i个字符串的哈希
int pos[N];//第i个字符串的位置
string s[N];
int ans[N];
signed main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>s[i];
hs[i]=s[i][0];
pos[i]=0;
mp[hs[i]].push_back(i);
}
for(int i=n;i>=1;i--)
{
ans[i]=mp.size();
ull HS=0;
for(auto j:s[i])
{
HS=HS*P+j;
auto it=mp.find(HS);
if(it==mp.end())
continue;
for(auto id:it->second)
{
if(id==i)
continue;
pos[id]++;
hs[id]=hs[id]*P+s[id][pos[id]];
mp[hs[id]].push_back(id);
}
mp.erase(it);
}
}
for(int i=1;i<=n;i++)
{
cout<<ans[i]<<endl;
}
}
F:Train Wreck(思维,模拟)
题意:
给你一个n,2*n的字符串序列以及长度为n的数组,字符串中“(”表示向栈push一个点,“)”表示向栈pop出去一个点,给每个点赋上数组中的一个值,要求任何时候栈中的序列都不相同(长度相同并且顺序相同)
solution:
假设当前有一个根结点1,假设每push一个点就新建一个点向上一个点连边然后转移到当前点,每pop一个点就回到上一个父亲结点,这样构造出一棵树,要求任何时候栈中的序列都不相同,其实就是从根节点1出发形成的每一条链都不相同,如何赋值保证不相同,只需要每一层的结点赋值不一样即可。模拟这个过程即可判断可不可以达成要求。
#include <bits/stdc++.h>
// #define int long long
using namespace std;
const int N=1e6+10;
int a[N];
map<int,int>mp;
int ans[N];
vector<int>edge[N];
int fa[N];
struct node{
int id,sum;
bool operator >(const node& b)const
{
return sum<b.sum;
}
}b[N];
signed main()
{
int n;
string s;
scanf("%d",&n);
cin>>s;
int cnt=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(!mp[x])
a[cnt++]=x;
mp[x]++;
}
int root=1;
int rt=1;
for(int i=0;i<2*n;i++)
{
if(s[i]=='(')
{
edge[root].push_back(++rt);
fa[rt]=root;
root=rt;
}
else
{
root=fa[root];
}
}
priority_queue<node,vector<node>,greater<node>>q;
stack<node>st;
for(int i=0;i<cnt;i++)
{
q.push({a[i],mp[a[i]]});
// cout<<a[i]<<" "<<mp[a[i]]<<endl;
}
// cout<<q.top().id;
// for(int i=1;i<=n+1;i++)
// {
// for(auto j:edge[i])
// {
// cout<<j<<" ";
// }
// cout<<endl;
// }
bool ok=true;
queue<int>s1,s2;
for(auto i:edge[1])
{
s1.push(i);
}
while(s1.size()||s2.size())
{
if(s1.size()!=0)
{
if(q.size()<s1.size())
{
ok=false;
break;
}
while(s1.size())
{
node fr=q.top();q.pop();
int num=s1.front();s1.pop();
ans[num]=fr.id;fr.sum--;
if(fr.sum!=0)
st.push(fr);
for(auto v:edge[num])
{
s2.push(v);
}
}
while(st.size())
{
node fr=st.top();
st.pop();
// if(fr.sum>0)
// {
q.push(fr);
// }
}
}
else
{
if(q.size()<s2.size())
{
ok=false;
break;
}
while(s2.size())
{
node fr=q.top();q.pop();
int num=s2.front();s2.pop();
ans[num]=fr.id;fr.sum--;
if(fr.sum!=0)
st.push(fr);
for(auto v:edge[num])
{
s1.push(v);
}
}
while(st.size())
{
node fr=st.top();
st.pop();
// if(fr.sum>0)
// {
q.push(fr);
// }
}
}
}
if(!ok)
{
cout<<"NO";
return 0;
}
cout<<"YES"<<endl;
for(int i=2;i<=n+1;i++)
{
cout<<ans[i]<<" ";
}
}