NAIPC2018
NAIPC2018
参考:http://www.cnblogs.com/LQLlulu/p/9513669.html?tdsourcetag=s_pctim_aiomsg
https://www.cnblogs.com/clrs97/p/8730429.html?tdsourcetag=s_pctim_aiomsg
E-Prefix Free Code
题目描述
Consider n initial strings of lower case letters, where no initial string is a prefix of any other initial string. Now, consider choosing k of the strings (no string more than once), and concatenating them together. You can make this many such composite strings:
n × (n − 1) × (n − 2) × . . . × (n − k + 1)
Consider sorting all of the composite strings you can get via this process in alphabetical order. You are given a test composite string, which is guaranteed to belong on this list. find the position of this test composite string in the alphabetized list of all composite strings, modulo 109 +7. The first composite string in the list is at position 1.
输入
Each input will consist of a single test case. Note that your program may be run multiple times on different inputs. Each test case will begin with a line with two integers, first n and then k(1 ≤ k ≤ n), where n is the number of initial strings, and k is the number of initial strings you choose to form composite strings. The upper bounds of n and k are limited by the constraints on the strings, in the following paragraphs.
Each of the next n lines will contain a string, which will consist of one or more lower case letters a..z. These are the n initial strings. It is guaranteed that none of the initial strings will be a prefix of any other of the initial strings.
finally, the last line will contain another string, consisting of only lower case letters a..z. This is the test composite string, the position of which in the sorted list you must find. This test composite string is guaranteed to be a concatenation of k unique initial strings.
The sum of the lengths of all input strings, including the test string, will not exceed 106 letters.
输出
Output a single integer, which is the position in the list of sorted composite strings where the test composite string occurs. Output this number modulo 109 + 7.
样例输入
5 3
a
b
c
d
e
cad
样例输出
26
一开始的思路:
用map把输入的字符串按字典序标记一个数字,因为涉及到排序和map 就要用string。然后再将要处理的字符串也化为数字,然后就是求这个排列是第几个,对于每位数字,减去前面有多少比它小的-1,然后乘以后面的全排列就好了。终于找前面有多少个比它小的,当然是暴力啦1e6/2=1e3最后半小时才意识到要用树状数组,然而还是内存超限。
正解:
怎么没想到字典树呢?好吧其实是想到的但是不会先建树,因为题中说没有单词是另一个单词的前缀,cnt[]维护每个单词的编号。然后再用一个num[]维护一下单词的字典次序,这个怎么维护呢?直接跑一遍tire,就可以了。num[cnt[u]]相当于之前方法的字符串转化为数字:正好复习一下tire模板
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+5;
const int mod=1e9+7;
int n,k,ant;
int s[maxn],c[maxn],cnt[maxn],num[maxn];
int tire[maxn][30];
ll f[1000010],invf[1000010];
char str[maxn];
ll qmul(ll a,ll b){ll ret=0; while(b){ if(b&1) ret=(ret+a)%mod; a=(a+a)%mod; b>>=1;} return ret;}
ll qpow(ll a,ll b){ll ret=1; while(b){ if(b&1) ret=qmul(ret,a); a=qmul(a,a); b>>=1;} return ret;}
void init(){
f[0]=1;
for(ll i=1;i<=1000001;i++) f[i]=f[i-1]*i%mod;
invf[1000001]=qpow(f[1000001],mod-2);
for(ll i=1000000;i>=0;i--) invf[i]=invf[i+1]*(i+1)%mod;
}
inline int lowbit(int x){return x&-x;}
inline void add(int x,int val){
for(int i=x;i<=n;i+=lowbit(i)){
c[i]+=val;
}
}
inline int getsum(int x){
int ret=0;
for(int i=x;i>0;i-=lowbit(i)){
ret+=c[i];
}
return ret;
}
void ins(char *str)
{
int len=strlen(str);
int p=0;
for(int i=0;i<len;i++){
int ch=str[i]-'a';
if(!tire[p][ch])
tire[p][ch]=++ant;
p=tire[p][ch];
}
cnt[p]++;
//cout<<p<<" "<<cnt[p]<<endl;
}
//int srh(char *str)
//{
// int ans=0;
// int len=strlen(str);
// int p=0;
// for(int i=0;i<len;i++){
// int ch=str[i]-'a';
// p=tire[p][ch];
// if(!p) return ans;
// ans+=cnt[p];
// }
// return ans;
//}
int op;
void cal(int u)
{
if(cnt[u]){
op++;
num[u]=op;
return;
}
for(int i=0;i<26;i++){
if(tire[u][i])
cal(tire[u][i]);
}
}
int main()
{
init();
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>n>>k){
ant=0;
memset(cnt,0,sizeof(cnt));
memset(tire,0,sizeof(tire));
memset(c,0,sizeof(c));
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++){
cin>>str;
ins(str);
}
cin>>str;
op=0;
cal(0);
ll ans=0;
ll t;
int x;
int u=0,id=0;
int len=strlen(str);
for(int i=0;i<len;i++){
t=str[i]-'a';
u=tire[u][t];
if(cnt[u]){
id++;
x=getsum(num[u]);
ans=(ans+qmul(qmul((num[u]-1-x),f[n-id]),invf[n-k]))%mod;
add(num[u],1);
u=0;
}
}
cout<<(ans+1)%mod<<endl;//%lxq
}
return 0;
}
比赛时疯狂瞎改,想尽了所有加快的方法,加了tire之后跑得超快,直接第一.....
NAIPC2018的更多相关文章
随机推荐
- UVA 10003 区间DP
这个题目蛮有新意的,一度导致我没看透他是区间DP 给一个0-L长度的木板,然后给N个数,表示0-L之间的某个刻度,最后要用刀把每个刻度都切一下 使其断开,然后每次分裂的cost是分裂前的木板的长度.求 ...
- SASS - 混合(Mixin)
SASS – 简介 SASS – 环境搭建 SASS – 使用Sass程序 SASS – 语法 SASS – 变量 SASS- 局部文件(Partial) SASS – 混合(Mixin) SASS ...
- Day 2:线程与进程系列问题(二)
补充: 线程的创建方式二: 1.自定义一个实现Runnable接口的类 2.实现Runnable接口中的run方法把自定义线程的任务写在run方法中 3.创建实现Runnable接口的对象 4.创建T ...
- 洛谷 P1968 美元汇率
题目传送门 解题思路: 一道很简单的DP AC代码: #include<iostream> #include<cstdio> using namespace std; int ...
- PHP集成环境wamp和navicat for mysql 的安装
1. PHP集成环境WAMP的安装: 下载wamp: 链接:https://pan.baidu.com/s/1zvoPEbLdG7y04WWHNM6UcA 密码:mxd3 安装过程如下图: 安装完成 ...
- BZOJ 3197 [Sdoi2013]assassin
题解: 树上Hash 首先重心在边上就把边分裂 以重心为根建树,这样两个根一定对应 然后f[i][j]表示i匹配另一棵的j节点的最小代价 把他们的儿子摘出来做最小权匹配即可 #include<i ...
- BZOJ [Cqoi2017] 小Q的棋盘
题解:枚举最后在哪里停止,然后剩下的步数/2 也就是找最大深度 枚举终止位置算是一种思路吧 #include<iostream> #include<cstdio> #inclu ...
- MySQL读写分离如何实现?
主要说下读写分离, 当我们的数据量很大时,数据库服务器的压力变大,这时候我们需要从架构方面来解决这一问题,在一个网站中读的操作很多,写的操作很少,这时候我们需要配置读写分离,把读操作和写操作分离出来, ...
- pycharm使用常见设置
字体修改: file——setting——Editor——font(快捷键:ctrl+alt+s) 修改项目编译器:a,b方法二选一 a.ctrl+alt+s,调出设置窗口——选中想要换的版本即可,如 ...
- [极客大挑战 2019]Havefun
打开题目右键查看源代码 <!--$cat=$_GET['cat']; echo $cat; if($cat=='dog') {echo 'Syc{cat_cat_cat_cat}';}--> ...