加载中…

返回上一页

2022NOIP A层联测23

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

zzy 的金牌

首先如果一个最终的集合能对答案做出贡献,显然如果对于全部的 i 满足每一个 si 都大于等于 ai∑ si - ∑ ai = k.

所以就是要去求序列 b1 , … , bn 的数量,满足:

  1. bi + ai ≥ bi−1 + ai−1
  2. ∑b = k.

感觉就是重复了一遍官方题解

dp[i][j][k] 表示序列 b 的前 i 项,满足 bi = jb 序列的前 i 项的和为 k,总共的方案数.

枚举 l,注意到合法的 l 一定是从 ai + k - ai+1(这里的 k 是指枚举的那个)开始的,直至 k - j.

状态转移方程

dp[i + 1][j + l][l] += dp[i][j][k].

答案显然是 ∑ dp[n][k][i].

需要卡常,加一下编译器优化和减少取模即可通过此题.

点击查看代码
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 301
#define mod 998244353
#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,k,a[maxn],dp[maxn][maxn][maxn],ans;
multiset<ll> s;
map<multiset<ll>,bool> mp;
#define mo(x) (x)>mod?x-=mod:NULL
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) (ans*=a)%=mod; (a*=a)%=mod; } return ans; }
inline void dfs(rll x)
{
	if(x==k) { s.clear(); for(rll i=1;i<=n;i++) s.insert(a[i]); mp[s]=0; return; }
	for(rll i=1;i<=n;i++) a[i]++,dfs(x+1),a[i]--;
}
int main()
{
	freopen("orzzy.in","r",stdin); freopen("orzzy.out","w",stdout);
	n=read();k=read(); for(rll i=1;i<=n;i++) a[i]=read(); 
	if(k<=8) { dfs(0);write(mp.size()%mod);return 0; } sort(a+1,a+n+1); dp[0][0][0]=1;
	for(rll i=0;i<n;i++) for(rll j=0;j<=k;j++) for(rll k1=0;k1<=j;k1++) if(dp[i][j][k1])
		for(rll l=max(0,a[i]+k1-a[i+1]);l<=k-j;l++) (dp[i+1][j+l][l]+=dp[i][j][k1]),mo(dp[i+1][j+l][l]);
	for(rll i=0;i<=k;i++) ans+=dp[n][k][i],mo(ans); write(ans%mod);
	return 0;
}

口粮输送

数据很小,自然想到状压.

dp[S] 表示点集 S 的子图是否有合法的方案.

枚举集合,用一个并查集维护每个集合子集的状态.

然后枚举每一条边,如果这条边的两个端点都在当前的这个集合中,就更新一下答案和总的边权. 如果所有点均在这个集合中且总权值足够,那么这个状态就是合法的.

最后由小状态传到大状态上统计一下.

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 16
#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'); }
struct node
{
	ll u,v,w;
	inline friend bool operator<(rg node a,rg node b) { return a.w<b.w; }
}e[1<<maxn];
ll t,n,m,a[maxn],f[maxn];
bool fl[1<<maxn],dp[1<<maxn];
inline ll find(rll x) { if(x^f[x]) f[x]=find(f[x]); return f[x]; }
int main()
{
	freopen("trans.in","r",stdin); freopen("trans.out","w",stdout);
	t=read(); while(t--)
	{
		n=read();m=read(); for(rll i=1;i<=m;i++) e[i]=(node){ read(),read(),read() }; sort(e+1,e+m+1);
		for(rll i=1,x;i<=n;i++) x=read(),a[i]=x-read(); memset(dp,0,sizeof(dp)); dp[0]=1;
		for(rll S=1,cnt,sum,cnt1,sum1;S<1<<n;S++)
		{
			cnt=sum=cnt1=sum1=0; for(rll i=1;i<=n;i++) if(S&(1<<i-1)) f[i]=i,cnt++,sum+=a[i];
			for(rll i=1;i<=m;i++) if((S&(1<<e[i].u-1))&&(S&(1<<e[i].v-1))&&(find(e[i].u)^find(e[i].v)))
				cnt1++,sum1+=e[i].w,f[find(e[i].u)]=find(e[i].v);
			fl[S]=cnt1==cnt-1&&sum1<=sum;
		}
		for(rll S=1;S<1<<n;S++) for(rll T=S;T;T=S&T-1) dp[S]|=dp[S^T]&fl[T]; puts(dp[(1<<n)-1]?"Yes":"No");
	}
	return 0;
}

作弊

先处理出来下面四个数组:

  1. i 边第一个大于等于 lia 的位置 lftl[i]

  2. i 边第一个大于等于 ria 的位置 lftr[i]

  3. i 边第一个大于等于 lia 的位置 rhtl[i]

  4. i 边第一个大于等于 ria 的位置 rhtr[i].

这个玩意怎么处理都可以. 树状数组、线段树、单调栈、优先队列等等. 我这里用的最后一个.

然后,去枚举每一个学生,把他能够成功达到预期分数的最大的那个区间每一个数都加上 1(刚才的那几个数组就派上用场了,就是处理出来比当前数大的左右的 l),在到了这个区间末端的时候减去 1(和刚才同理,就是到 r 的区间).

最后答案即是整个区间的最大值.

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 100001
#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'); }
struct tree
{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
	ll v,tag;
}t[maxn<<2];
ll n,a[maxn],l[maxn],r[maxn];
ll lftl[maxn],lftr[maxn],rhtl[maxn],rhtr[maxn];
priority_queue<pll,vector<pll>,greater<pll> > q1,q2;
vector<ll> g1[maxn],g2[maxn];
#define pushup(rt) t[rt].v=max(t[ls(rt)].v,t[rs(rt)].v)
inline void pushdown(rll rt)
{
	if(t[rt].tag) t[ls(rt)].v+=t[rt].tag,t[rs(rt)].v+=t[rt].tag,
		t[ls(rt)].tag+=t[rt].tag,t[rs(rt)].tag+=t[rt].tag,t[rt].tag=0;
}
inline void upd(rll rt,rll l,rll r,rll x,rll y,rll v)
{
	// if(y<l||x>r) return;
	if(x<=l&&r<=y) { t[rt].v+=v;t[rt].tag+=v;return; } pushdown(rt); rll mid=(l+r)>>1;
	if(x<=mid) upd(ls(rt),l,mid,x,y,v); if(y>mid) upd(rs(rt),mid+1,r,x,y,v); pushup(rt);
}
/*inline void upd(rll rt,rll l,rll r,rll pos,rll v)
{
	if(l==r) { t[rt].v=max(t[rt].v,v);return; } pushdown(rt); rll mid=(l+r)>>1;
	if(pos<=mid) upd(ls(rt),l,mid,pos,v); else upd(rs(rt),mid+1,r,pos,v); pushup(rt);
}*/
int main()
{
	freopen("cheat.in","r",stdin); freopen("cheat.out","w",stdout);
	n=read(); for(rll i=1;i<=n;i++) a[i]=read(); for(rll i=1;i<=n;i++) l[i]=read(),r[i]=read();
	for(rll i=1;i<=n;i++)
	{
		while((!q1.empty())&&a[i]>=q1.top().first) rhtl[q1.top().second]=i,q1.pop();
		while((!q2.empty())&&a[i]>q2.top().first) rhtr[q2.top().second]=i,q2.pop();
		if(a[i]<l[i]) q1.push((pll) { l[i],i }); else rhtl[i]=i;
		if(a[i]<=r[i]) q2.push((pll) { r[i],i }); else rhtr[i]=i;
	}
	while(!q1.empty()) q1.pop(); while(!q2.empty()) q2.pop();
	for(rll i=n;i;i--)
	{
		while((!q1.empty())&&a[i]>=q1.top().first) lftl[q1.top().second]=i,q1.pop();
		while((!q2.empty())&&a[i]>q2.top().first) lftr[q2.top().second]=i,q2.pop();
		if(a[i]<l[i]) q1.push((pll) { l[i],i }); else lftl[i]=i;
		if(a[i]<=r[i]) q2.push((pll) { r[i],i }); else lftr[i]=i;
	}
	// for(rll i=1;i<=n;i++) cout<<lftl[i]<<' '<<lftr[i]<<' '<<rhtl[i]<<' '<<rhtr[i]<<endl;
	for(rll i=1;i<=n;i++) { if(rhtl[i]) g1[rhtl[i]].emplace_back(i); if(rhtr[i]) g2[rhtr[i]].emplace_back(i); }
	for(rll i=1;i<=n;i++)
	{
		upd(1,1,n,i,i,t[1].v); if(lftl[i]) upd(1,1,n,1,lftl[i],1); if(lftr[i]) upd(1,1,n,1,lftr[i],-1);
		for(rll j=0;j<g1[i].size();j++) if(lftl[g1[i][j]]<g1[i][j]) upd(1,1,n,lftl[g1[i][j]]+1,g1[i][j],1);
		for(rll j=0;j<g2[i].size();j++) if(lftr[g2[i][j]]<g2[i][j]) upd(1,1,n,lftr[g2[i][j]]+1,g2[i][j],-1);
	}
	write(t[1].v);
	return 0;
}

合作的力量

没改.

posted @ 2022-11-08 19:07  1Liu  阅读(31)  评论(0)    收藏  举报