模拟3

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);
}

  

posted on 2022-05-15 17:47  HZOI-曹蓉  阅读(237)  评论(0)    收藏  举报