加载中…

返回上一页

2022NOIP A层联测19

下发文件(密码为原 accoders 比赛密码)

皮胚

暴力或者 dp.

这里讲前面那个. 直接将两个串的哈希搞出来,拿一个 set 维护到从 1 到当前端点的区间里有多少合法的序列,分三种情况讨论一下.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 2001
#define ull unsigned ll
#define bs 131
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll T,n,m,eds[maxn];
char s[maxn],t[maxn];
ull hss[maxn],hst[maxn],mi[maxn];
set<ll> g,h;
inline ll geths(rll l,rll r,rg char s) { if(s=='s') return hss[r]-hss[l-1]*mi[r-l+1]; else return hst[r]-hst[l-1]*mi[r-l+1]; }
int main()
{
	freopen("match.in","r",stdin); freopen("match.out","w",stdout);
	mi[0]=1; for(rll i=1;i<maxn;i++) mi[i]=mi[i-1]*bs; T=read();while(T--)
	{
		scanf("%s",s+1);n=strlen(s+1); scanf("%s",t+1);m=strlen(t+1); g.clear();g.insert(1);
		for(rll i=1;i<=n;i++) hss[i]=hss[i-1]*bs+s[i]; for(rll i=1;i<=m;i++) hst[i]=hst[i-1]*bs+t[i];
		for(rll i=n;i;i--) if(s[i]==s[i+1]) eds[i]=eds[i+1]; else eds[i]=i;
		for(rll i=1;i<=m;i++)
		{
			if(t[i]=='*')
			{
				rll sz=g.size();h=g;
				for(rg set<ll>::iterator j=g.begin();j!=g.end();j++) for(rll k=(*j);k<=eds[(*j)-1];k++) h.insert(k+1); g=h;
			}
			else if(t[i]=='.')
			{
				h.clear(); for(rg set<ll>::iterator j=g.begin();j!=g.end();j++) if((*j)==n+1); else h.insert((*j)+1); g=h;
			}
			else
			{
				h.clear(); rll j=i;while(j<m&&(t[j+1]^'*')&&(t[j+1]^'.')) j++;
				for(rg set<ll>::iterator k=g.begin();k!=g.end();k++)
					if(n-(*k)+1<j-i+1||(geths(i,j,'t')^geths((*k),(*k)+j-i,'s')));
					else h.insert((*k)+j-i+1);
				i=j;g=h;
			}
		}
		write(g.size());putn;
		// sort(g.begin(),g.end());write(unique(g.begin(),g.end())-g.begin());putn;
		// write(g.size());putn;for(rll i=0;i<g.size();i++) write(g[i]),put_;putn;
	}
	return 0;
}

dp 做法:

没写这种做法不放码了.

其实两种做法的实质是一样的.

核冰

  1. 暴力做法,显然. 我用了个 mapset 做的.
点击查看代码
#include<bits/extc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 500001
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,m,pos,a[maxn];
__gnu_pbds::gp_hash_table<ll,ll> mp;
ll num[maxn];
__gnu_pbds::priority_queue<pll> q;
unordered_set<ll> s;
int main()
{
	freopen("merge.in","r",stdin); freopen("merge.out","w",stdout);
	n=read();m=read(); for(rll i=1;i<=n;i++) mp[a[i]=read()]++;
	while(m--) switch(read())
	{
	case 1:pos=read();mp[a[pos]]--;if(!mp[a[pos]]) mp.erase(a[pos]);mp[a[pos]=read()]++;break;
	case 2:
		s.clear();memset(num,0,sizeof(num));
		for(rg __gnu_pbds::gp_hash_table<ll,ll>::iterator i=mp.begin();i!=mp.end();i++)
			num[(*i).first]=(*i).second,q.push((pll) { (*i).second,(*i).first });// ,cout<<(*i).first<<' '<<q.size()<<endl;cout<<endl;
		while(1)
		{
			rll id=(q.top()).second,t=q.top().first,p,k;
			while((!q.empty())&&(t^num[id])) { q.pop();if(q.empty()) break; id=(q.top()).second,t=q.top().first; }
			// cout<<id<<' '<<t<<endl;
			if(q.empty()||t<=2) break; p=(t>>1)-!(t&1),k=1+!(t&1);
			q.pop();num[id]=k; q.push((pll) { num[id],id });
			num[id+1]+=p;q.push((pll) { num[id+1],id+1 });
		}
		while(!q.empty()) s.insert(q.top().second),q.pop();
		write(s.size());putn;
		break;
	}
	return 0;
}
  1. 尝试优化. 首先把所有的全部更新一下. 发现最优的方案一定是把每个数保留到仅剩两个或. 然后每次修改的时候如果删除之后没有了,就从前边要回来. 能够获得 80 分,最后两个点会超时.
点击查看代码
#pragma GCC optimize(1,2,3,"Ofast","inline")// 这个优化在这儿没什么用,去掉也是最后两个点T
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 500101
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,m,pos,x,a[maxn],ans;
ll cnt[maxn],num[maxn];
int main()
{
	freopen("merge.in","r",stdin); freopen("merge.out","w",stdout);
	n=read();m=read(); for(rll i=1;i<=n;i++) a[i]=read(),cnt[a[i]]++;
	for(rll i=1;i<maxn;i++) { if(cnt[i]) ans++; if(cnt[i]>2) cnt[i+1]+=(num[i]=(cnt[i]>>1)-!(cnt[i]&1)),cnt[i]=1+!(cnt[i]&1); }
	while(m--) switch(read())
	{
	case 1:
		pos=read();x=read();
		cnt[a[pos]]--;if(!cnt[a[pos]])
		{
			if(!num[a[pos]]) ans--;
			else
			{
				rll t=a[pos]+1;while(cnt[t]==1&&num[t]) t++;// ,cout<<t<<' '<<cnt[t]<<endl;// 这里改成二分
				if(!cnt[t]) t--; cnt[t]--; if(!cnt[t]) ans--; for(rll i=a[pos];i<t;i++) num[i]--,cnt[i]++;// 这里改线段树
				cnt[a[pos]]++;
			}
		}
		if(!cnt[x]) ans++; cnt[a[pos]=x]++; if(cnt[x]>2)
		{
			rll t=x; while(cnt[t]>2) { cnt[t+1]++,num[t]++,cnt[t]-=2; t++; }
			if(cnt[t]==1) ans++;
		}
		break;
	case 2:write(ans);putn;break;
	}
	return 0;
}
  1. 线段树优化

发现经常用到区间更新,这个更新计数有几千万次.

因此上一个线段树,维护剩余 1 的数的标记,进行二分,然后找到第一个不是的位置更新. 注意特判一下边界:全部为 0 的情况.

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 501001
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,m,pos,x,a[maxn+1],cnt[maxn+1],ans;
class tree
{
public:
	struct node
	{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
		ll v,tag;bool tg1,tg2;
	}t[maxn+1<<2];
#define pushup(rt) t[rt].v=min(t[ls(rt)].v,t[rs(rt)].v),t[rt].tg1=t[ls(rt)].tg1&t[rs(rt)].tg1,t[rt].tg2=t[ls(rt)].tg2&t[rs(rt)].tg2
	inline void build(rll rt,rll l,rll r)
	{
		if(l==r) { t[rt].v=cnt[l];t[rt].tg1=!(cnt[l]&1);t[rt].tg2=cnt[l]&1; return; } rll mid=(l+r)>>1;
		build(ls(rt),l,mid);build(rs(rt),mid+1,r);pushup(rt);
	}
	inline void pushdown(rll rt)
	{
		if(t[rt].tag)
			t[ls(rt)].v+=t[rt].tag,t[rs(rt)].v+=t[rt].tag,
			(t[rt].tag&1?(swap(t[ls(rt)].tg1,t[ls(rt)].tg2),swap(t[rs(rt)].tg1,t[rs(rt)].tg2)):void()),
			t[ls(rt)].tag+=t[rt].tag,t[rs(rt)].tag+=t[rt].tag,t[rt].tag=0;
	}
	inline void upd(rll rt,rll v) { t[rt].v+=v;t[rt].tag+=v; swap(t[rt].tg1,t[rt].tg2); }
	inline ll add(rll rt,rll l,rll r,rll pos)
	{
		if(pos<=l)
		{
			if(t[rt].tg1&&t[rt].v) { upd(rt,1); return r; }
			if(l==r) { if(!t[rt].v) t[rt].v=1,t[rt].tg1=0,t[rt].tg2=1,ans++; else upd(rt,1); return r-1; }
			pushdown(rt); rll mid=(l+r)>>1,p=add(ls(rt),l,mid,pos);
			if(p==mid) p=add(rs(rt),mid+1,r,pos); pushup(rt);return p;
		}
		pushdown(rt);rll mid=(l+r)>>1,p;
		if(pos<=mid) { p=add(ls(rt),l,mid,pos); if(p==mid) p=add(rs(rt),mid+1,r,pos); }
		else p=add(rs(rt),mid+1,r,pos); pushup(rt); return p;
	}
	inline ll del(rll rt,rll l,rll r,rll pos)
	{
		if(pos<=l)
		{
			if(t[rt].tg2&&t[rt].v>1) { upd(rt,-1);return r; }
			if(l==r)
			{
				if(t[rt].v==1)t[rt].v=0,t[rt].tg1=1,t[rt].tg2=0,ans--;
				else upd(rt,-1); return r-1;
			}
			pushdown(rt); rll mid=(l+r)>>1,p=del(ls(rt),l,mid,pos);
			if(p==mid) p=del(rs(rt),mid+1,r,pos); pushup(rt); return p;
		}
		pushdown(rt);rll mid=(l+r)>>1,p;
		if(pos<=mid) { p=del(ls(rt),l,mid,pos); if(p==mid) p=del(rs(rt),mid+1,r,pos); }
		else p=del(rs(rt),mid+1,r,pos); pushup(rt);return p;
	}
}t;
int main()
{
	freopen("merge.in","r",stdin); freopen("merge.out","w",stdout);
	n=read();m=read(); for(rll i=1;i<=n;i++) cnt[a[i]=read()]++;
	for(rll i=1;i<maxn;i++) if(cnt[i]) cnt[i+1]+=(cnt[i]-1>>1),ans++;
	t.build(1,1,maxn-1);
	while(m--) switch(read())
	{
	case 1:
		pos=read();x=read();t.del(1,1,maxn-1,a[pos]);a[pos]=x;t.add(1,1,maxn-1,x); break;
	case 2:write(ans);putn;break;
	}
	return 0;
}

方珍

mex 的过程很简单,看代码:

inline ll add(rll x) { mex[x]=1; while(mex[ls]) ls++; return ls; }
for(rll i=1;i<=n;i++)
{
	memset(mex,0,sizeof(mex));ls=0;
	for(rll j=i;j<=n;j++) cnt[add(a[j])]++;
}

然后就是一个找第 kmex 值的过程:

for(rll i=0;i<=n;i++) if(k-cnt[i]>0) k-=cnt[i]; else { ls=i;break; }

这是暴力. 考虑如何优化:

把所有数组按照 wi 进行降序排序,这样保证了答案的单调性. 最后每次取最大值,如果变小了证明后边的答案没有贡献,直接跳出.

据说这种方法好像是乱搞,但是一般也很不好卡

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 10001
#define ull unsigned long long
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
template<typename T>
inline T read()
{
	rg bool f=0;rg T x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
struct node
{
	ll k,w,m; ull seed;
	inline friend bool operator<(rg node a,rg node b) { return a.w>b.w; }
}b[maxn];
ll n,a[maxn],cnt[maxn],ans,ls;
bool mex[maxn];
inline ull _rand(rg node& a) { a.seed^=a.seed<<13;a.seed^=a.seed>>7;a.seed^=a.seed<<17;return a.seed; }
inline void read_test()
{
	for(rll i=1;i<=n;i++) b[i].k=read<ll>(),b[i].w=read<ll>(),b[i].m=read<ll>(),b[i].seed=read<ull>();
}
inline void test(rll t) { for(rll i=1;i<=n;i++) a[i]=_rand(b[t])%b[t].m; }
inline ll add(rll x) { mex[x]=1; while(mex[ls]) ls++; return ls; }
int main()
{
	freopen("mex.in","r",stdin); freopen("mex.out","w",stdout);
	// freopen("out.txt","w",stdout);
	n=read<ll>();read_test();sort(b+1,b+n+1);for(rll t=1;t<=n;t++)
	{
		test(t);rll k=b[t].k,w=b[t].w; for(rll i=0;i<=n;i++) cnt[i]=0;
		for(rll i=1;i<=n;i++)
		{
			memset(mex,0,sizeof(mex));ls=0;
			for(rll j=i;j<=n;j++) cnt[add(a[j])]++;
		}
		// for(rll i=1;i<=n;i++) cout<<a[i]<<' ';cout<<endl;
		// cout<<cnt[0]<<' '<<k<<' ';
		for(rll i=0;i<=n;i++) if(k-cnt[i]>0) k-=cnt[i]; else { ls=i;break; }
		// cout<<w<<' '<<ls<<endl;
		if(ans<w+ls) ans=w+ls;  else break;
		// if(ans+1-w<ls) break;
	}
	write(ans);
	return 0;
}

术劣

没改……

posted @ 2022-11-01 19:38  1Liu  阅读(92)  评论(0)    收藏  举报