2022NOIP A层联测23
下发文件(密码为原 accoders 比赛密码)
zzy 的金牌
首先如果一个最终的集合能对答案做出贡献,显然如果对于全部的 i 满足每一个 si 都大于等于 ai 且 ∑ si - ∑ ai = k.
所以就是要去求序列 b1 , … , bn 的数量,满足:
- bi + ai ≥ bi−1 + ai−1;
- ∑b = k.
感觉就是重复了一遍官方题解
设 dp[i][j][k] 表示序列 b 的前 i 项,满足 bi = j 且 b 序列的前 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;
}
作弊
先处理出来下面四个数组:
-
点 i 左边第一个大于等于 li 的 a 的位置 lftl[i];
-
点 i 左边第一个大于等于 ri 的 a 的位置 lftr[i];
-
点 i 右边第一个大于等于 li 的 a 的位置 rhtl[i];
-
点 i 右边第一个大于等于 ri 的 a 的位置 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;
}
合作的力量
没改.
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16870850.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!