T3.tire树或者map映射,第一种高效10倍,待会再理解
#include<bits/stdc++.h>
using namespace std;
const int maxn = (1e4+10)*50;
int tree[maxn][26],v[maxn][26],cnt[maxn][26],len,tot;
char s[26];
void add(int l, int r, int id){
int rt = 0,t;
while(l < r){//因为要看是否存在于字符串中而不是 是否为前缀 所以要把一个字符串以每个字符为起点存一次
t = s[l] - 'a';//将字母转化为对应的下标
if (tree[rt][t]) {//如果当前的字母已经建过节点
if (v[rt][t] != id) {
v[rt][t] = id;
++cnt[rt][t];//当前字符串++
}
}
else {//如果还没有建过当前节点
tree[rt][t] = ++tot;//新建一个点
v[rt][t] = id;
cnt[rt][t]++;
}
rt = tree[rt][t];
++l;
}
}
int search(){
int rt = 0,ans = 0;
for(int i = 0;i < len;++i){
if(!tree[rt][s[i]-'a'])return 0;//如果当前字符未出现过
ans = cnt[rt][s[i]-'a'];//即为当前字符串出现的次数
rt = tree[rt][s[i]-'a'];//为下一次转移做准备
}
return ans;
}
int main(){
freopen("mdz.in","r",stdin);
freopen("mdz.out","w",stdout);
int n;scanf("%d",&n);
for(int i = 0;i < n;++i){
scanf("%s",s);
len = strlen(s);
for(int j = 0;j < len;++j){
add(j,len,i);
}
}
int m;scanf("%d",&m);
while(m--){
scanf("%s",s);
len = strlen(s);
printf("%d\n",search());
}
}
C. SSY的队列 - 高一普及组模拟赛3 - 比赛 - 衡中OI (hszxoj.com)
方法:状态压缩+hash+dfs+记忆化
思路:
首先想到容斥原理,用所有的方案减去一个相同挨着的+两个相同挨着的,但是去重太麻烦,而且各个方案之间相互牵连,不方便实现
那么再仔细看题,可不可以对问题进行简化?
相邻的数差值是m的倍数,那全部摸上m,其实就是余数相同的不能放在一起
问题就抽象成了(3个red,5个blue,7个green排列相同颜色不挨着的方案数),深搜
dfs(dep,lst)第几个位置,上一个哪个种类,O(n^n)超时
发现,如果我知道当前lst组还剩下的人数,接下来还可以用的组别剩的人数分别有几组,我就可以从上面已求出状态转移过来
这个记忆化相当于大大减少了时复杂度O(n^n-相当多的一部分)
1处处特殊处理
const int N=40;
const ll mod=1234567891,base=33;
int a[N],b[N],c[N],mx,cnt;
map<ll,ll>dp[N];//数组开不下
int n,m;
ll fac[N];
inline ll dfs(int dep,int lst)
{
if(dep>n)return 1;
memset(b,0,sizeof(b));
_f(i,1,cnt)//0不用算吧?至少不能一起算
{
if(i!=lst)b[c[i]]++;
}
ll st=c[0];//b[i]=j,剩余人数是i的组有j个
_f(i,1,mx)//剩余人数是0个的组数我压根就没算
{
st=st*base+b[i];
}
st=st*base+((lst)?c[lst]:0);//表示对后边没有影响
if(dp[dep].count(st))return dp[dep][st];//开始统计
ll ans=0;
if(c[0])
{
c[0]--;
ans+=dfs(dep+1,0);
c[0]++;
ans%=mod;
}
_f(i,1,cnt)//下一个位置放哪一类人
{
if(i!=lst)
{
if(!c[i])continue;
c[i]--;
ans+=dfs(dep+1,i);
c[i]++;
ans%=mod;
}
}
return dp[dep][st]=ans;
}
bool vis[N];
int main()
{
freopen("ssy.in","r",stdin);
freopen("ssy.out","w",stdout);
n=re();
_f(i,1,n)
{
a[i]=re();
}
m=re();
_f(i,1,n)
{
a[i]%=m;
if(a[i]<0)a[i]+=m;//负数的话摸出来也是负数,特殊加一下
}
_f(i,1,n)
{
if(vis[i])continue;
vis[i]=1;
int ret=1;
_f(j,i+1,n)
{
if(a[i]==a[j])vis[j]=1,ret++;
}
if(ret==1)c[0]++;//c[i]模数是相同的人分别有几个
else c[++cnt]=ret;//Cnt没有实际意义
mx=max(mx,ret);
}
fac[0]=1;ll ans=1;
_f(i,1,n)fac[i]=fac[i-1]*i%mod;
_f(i,0,cnt)ans=ans*fac[c[i]]%mod;
ll po=dfs(1,0);
ans=ans*po%mod;
chu("%lld",ans);
return 0;
}
T4
法一:跑最短路,处理连边的时候倒着连0,就跑出来了(非常妙!!!)
const int N=5e5+5;
int a[N];
int n,m,ee;
int tot;
struct node
{
int to,nxt,w;
}e[N<<2];
int head[N];
inline void add(int fr,int to,int va)
{
e[++tot].to=to,e[tot].nxt=head[fr],head[fr]=tot;e[tot].w=va;
}
queue<int>t;
int dis[N],vis[N];
void dij()//从m-->e
{
dis[m]=0;
t.push(m);
int ans=inf;
while(!t.empty())
{
// chu("take out:%d\n",t.front());
int u=t.front();
t.pop();
vis[u]=0;
for(R int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
//chu("%d to%d\n",u,v);
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(v>ee)ans=min(ans,dis[v]);
// chu("dis[%d]:%d\n",v,dis[v]);
if(!vis[v])
t.push(v);
vis[v]=1;
}
}
}
if(ans==inf)chu("-1");
else chu("%d",ans);
}
int main()
{
freopen("clean.in","r",stdin);
freopen("clean.out","w",stdout);
memset(dis,0x7f,sizeof(dis));
n=re(),m=re(),ee=re();
int maxi=ee+1,mii=m;
_f(i,1,n)
{
int t1=re(),t2=re(),s=re();
add(t1,t2+1,s);
maxi=max(maxi,max(t1,t2));
mii=min(mii,min(t1,t2));
}
maxi=maxi+1;
_f(i,mii,maxi)
add(i,i-1,0);
dij();
return 0;
}
法二:线段树维护dp,区间最小值
f[i]=min(f[i],f[j]+cow[k])//l[k]-1<=j<=r[k]-1
const int N=5e5+10;
struct node
{
int ls,rs,data;
}t[N<<4];
int tot=1;
int n,m,e;
void pushdown(int rt)
{
if(rt)
{
if(!lson)t[rt].data=t[rson].data;
else if(!rson)t[rt].data=t[lson].data;
else t[rt].data=min(t[lson].data,t[rson].data);
}
return;
}
inline int merge(int rt,int l,int r,int pos,int d)
{
if(!rt){
rt=++tot;
t[rt].data=inf;
}
if(l==r)
{
t[rt].data=min(t[rt].data,d);
return rt;
}
int mid=(l+r)>>1;
if(pos<=mid)t[rt].ls=merge(lson,l,mid,pos,d);
else t[rt].rs=merge(rson,mid+1,r,pos,d);
pushdown(rt);
return rt;
}
inline int query(int rt,int l,int r,int ll,int rr)
{
if(!rt)return inf;
if(ll<=l&&r<=rr)
{
return t[rt].data;
}
int ans=inf;
int mid=(l+r)>>1;
if(ll<=mid)ans=query(lson,l,mid,ll,rr);
if(rr>mid)ans=min(ans,query(rson,mid+1,r,ll,rr));
return ans;
}
struct node2
{
int t1,t2,s;
bool operator<(const node2&a)const
{
return t2<a.t2;
}
}cow[N];
int f[N];
int lll=inf,rrr;
int main()
{
freopen("clean.in","r",stdin);
freopen("clean.out","w",stdout);
n=re(),m=re()+2,e=re()+2;
_f(i,1,n)
{
cow[i].t1=re()+2,cow[i].t2=re()+2,cow[i].s=re();
lll=min(lll,cow[i].t1);
rrr=max(rrr,cow[i].t2);
}
sort(cow+1,cow+1+n);
_f(i,m,rrr)f[i]=inf;
merge(1,lll-1,rrr,m-1,0);
_f(i,1,n)
{
int rr=cow[i].t2,ll=cow[i].t1;
if(ll>e||rr<m)continue;
f[rr]=min(f[rr],query(1,lll-1,rrr,ll-1,rr-1)+cow[i].s);
merge(1,lll-1,rrr,rr,f[rr]);
}
int ans=inf;
_f(i,e,rrr)
ans=min(ans,f[i]);
if(ans==inf)chu("-1");
else chu("%d",ans);
}