前言

好像每个题目背景所描述的人都是某部番里的角色,热切好像都挺惨的(情感上的惨)。

然后我只知道 T1 的莓,确实挺惨。。。

T1 莓良心

解题思路

首先答案只与 \(w\) 的和有关系,于是问题就变成了对于一个点求出每一个所在组的大小以及对应的方案数。

考场上想的是枚举组的大小,然后预处理一下 \(n\) 个数字划分为 \(m\) 个非空集合的方案数。

一开始想的是隔板法,显然不对,然后就尝试 DP 计算,就有了 \(f_{i,j}=f_{i-1,j}\times j+f_{i-1,j-1}\)

一直想矩阵快速幂,看了半天才发现这 TM 两维,我优化个鬼!!

考完之后才知道这个是第二类斯特林数,然后才发现这玩意可以 NTT 暴算求出来一行或者一列的值,是我浅薄了。。。

官方题解的做法非常不一样,对于一对数 \(u,v\) 当两者被分到一个组中就会多出来 \(w_u+w_v\) 的贡献。

然后答案就是 \((\sum\limits_{i=1}^n w_i)\times(\;{n \brace k}+(n-1)\times {n-1 \brace k}\;)\)

发现可以直接容斥去求:

\[\displaystyle{n \brace k}=\frac{1}{k!}\sum_{i=0}^k(-1)^i \binom{k}{i}(k-i)^n
\]

然后 \(\mathcal{O}(n)\) 的线性筛或者 \(\mathcal{O}(nlogn)\) 的快速幂均可。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e6+10,M=2e3+10,mod=998244353;
int n,m,ans,base,fac[N],ifac[N] ;
int power(int x,int y,int p=mod)
{
int temp=1;
while(y)
{
if(y&1) temp=temp*x%p;
x=x*x%p; y>>=1;
}
return temp;
}
int C(int x,int y){return fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
int STL(int x,int y)
{
int temp=0;
for(int i=0,bas=1;i<=y;i++,bas=-bas) temp=(temp+bas*C(y,i)*power(y-i,x)%mod+mod)%mod;
return temp*ifac[y]%mod;
}
#undef int
int main()
{
#define int long long
freopen("ichigo.in","r",stdin); freopen("ichigo.out","w",stdout);
n=read(); m=read(); fac[0]=ifac[0]=1;
for(int i=1;i<=n;i++) base=(base+read())%mod,fac[i]=fac[i-1]*i%mod;
ifac[n]=power(fac[n],mod-2); for(int i=n-1;i>=1;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
printf("%lld",base*(STL(n,m)%mod+STL(n-1,m)%mod*(n-1)%mod)%mod);
return 0;
}

T2 尽梨了

解题思路

比较直接的一个 DP 就是 \(f_{i,j}\) 前 \(i\) 个商店买 \(j\) 个物品的最短时间。

发现在 \(a_i\) 不为 0 时,增长是指数级别的,于是每次转移只要 \(log\) 次就够了。

然后就是对于 \(a_i\) 为 0 的情况进行处理了,直接维护一个前缀和二分即可。

代码实现上有一些小细节。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e5+10;
int n,m,ans,pos,lim,f[N],pre[N];
struct Node{int a,b;}s[N];
bool comp(Node x,Node y){x.b++;y.b++;if(x.b*y.a!=y.b*x.a)return x.b*y.a<y.b*x.a;return x.b<y.b;}
#undef int
int main()
{
#define int long long
freopen("eriri.in","r",stdin); freopen("eriri.out","w",stdout);
n=read(); m=read(); lim=(int)log2(m)+1; memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++) s[i].a=read(),s[i].b=read();
f[0]=0; sort(s+1,s+n+1,comp); pos=n+1;
for(int i=1;i<=n;i++) if(!s[i].a){pos=i;break;}
for(int i=1;i<=n;i++) s[i].b+=s[i].a+1,s[i].a++;
for(int i=pos;i<=n;i++) pre[i]=pre[i-1]+s[i].b;
for(int i=1;i<pos;i++)
for(int j=min(i,lim);j>=1;j--)
if(f[j-1]<=m) f[j]=min(f[j],f[j-1]*s[i].a+s[i].b);
for(int i=0;i<=min(n,lim);i++)
{
if(f[i]>m) continue;
int l=pos,r=n,temp=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(pre[mid]<=m-f[i]) temp=mid,l=mid+1;
else r=mid-1;
}
ans=max(ans,i+((~temp)?temp-pos+1:0));
}
printf("%lld",ans);
return 0;
}

T3 团不过

解题思路

很妙的一个题。

设 \(p(i)\) 表示 \(i\) 堆石子的方案数 \(p(i)=(2^n-1)^{\underline{i}}\) 。

设 \(f(n)\) 表示 \(n\) 堆石子先手必败的方案数,转移考虑在 \(i-1\) 堆石子后再添加一堆与 \(i-1\) 堆异或和相等的石子堆。

也就是 \(p(n-1)\) ,但是如果 \(i-1\) 堆石子异或和已经是 0 那么显然是不合法的,需要减去。

还有一种情况就是 \(i-2\) 堆石子的异或和为 0 新加入了两堆相同的石子,显然也是不可以的,也需要减去。

因此就有了:

\[f(i)=p(i-1)-f(i-1)-f(i-2)\times(i-1)\times(2^n-i+1)
\]

直接递推,然后拿总方案数减去就好了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e7+10,mod=1e9+7;
int n,p[N],p2[N],f[N];
#undef int
int main()
{
#define int long long
freopen("yui.in","r",stdin); freopen("yui.out","w",stdout);
n=read(); p2[0]=1; for(int i=1;i<=n;i++) p2[i]=p2[i-1]*2%mod;
p[0]=1; for(int i=1;i<=n;i++) p[i]=p[i-1]*(p2[n]-i)%mod;
for(int i=3;i<=n;i++) f[i]=(p[i-1]-f[i-1]-(i-1)*f[i-2]%mod*(p2[n]-i+1)%mod+2*mod)%mod;
printf("%lld",(p[n]-f[n]+mod)%mod);
return 0;
}

T4 七负我

解题思路

最优的策略就是我们把所有的值都平均分配到一个完全图中,可以用 调整法 来证明。

然后直接枚举是 \(2^n\) 的无法接受,考虑 \(meet\;in\;the\;middle\)

于是枚举前 \(\frac{n}{2}\) 里的完全图,然后看他对于后 \(\frac{n}{2}\) 个点的连边。

再预处理出后 \(\frac{n}{2}\) 个点所有点集的所包含的完全图的个数。

然后枚举前 \(\frac{n}{2}\) 个点的点集,然后看他们对于后 \(\frac{n}{2}\) 连边的并集合并即可。

代码里好像有一个细节错了,但是错的那个点小于20,我直接。。。组合拳??

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=50;
int n,m,m1,m2,all,maxn,e[N],f[1<<20];
#undef int
int main()
{
#define int long long
freopen("nanami.in","r",stdin); freopen("nanami.out","w",stdout);
n=read(); m=read(); all=read(); m1=n>>1; m2=n-m1; if(n<=20) m1=n;
for(int i=1,x,y;i<=m;i++) x=read(),y=read(),e[x]|=1ll<<y-1,e[y]|=1ll<<x-1;
for(int sta=1;sta<(1ll<<m1);sta++)
{
int sum=__builtin_popcount(sta); if(sum<=maxn) continue;
for(int i=1;i<=m1;i++) if((sta>>i-1)&1) if((e[i]&sta)!=(sta^(1ll<<i-1))) goto X;
maxn=max(maxn,sum);X:;
}
if(n<=20) printf("%.6lf",(1.0*(maxn*(maxn-1)/2))*(1.0*all)/(1.0*maxn)*(1.0*all)/(1.0*maxn)),exit(0);
for(int sta=1;sta<(1ll<<m2);sta++)
{
int sum=__builtin_popcount(sta);
for(int i=1;i<=m2;i++) if((sta>>i-1)&1) if(((e[i+m1]>>m1)&sta)!=(sta^(1ll<<i-1))) goto Y;
f[sta]=sta; maxn=max(maxn,sum); Y:;
}
for(int sta=0;sta<(1ll<<m2);sta++)
{
int U=(1ll<<m2)-1,sum=__builtin_popcount(sta);
for(int i=1;i<=m2;i++) if((sta>>i-1)&1) U&=e[i+m1]>>m1;
if(!U&&sum!=1) continue;
for(int i=1;i<=m2;i++)
if((((sta>>i-1)&1)^1))
if((((e[i+m1]>>m1)&sta)==sta&&(U&(1ll<<i-1)))){if(__builtin_popcount(f[sta|(1ll<<i-1)])<sum+1) f[sta|(1ll<<i-1)]=f[sta]|(1ll<<i-1);}
else if(__builtin_popcount(f[sta|(1ll<<i-1)])<sum) f[sta|(1ll<<i-1)]=f[sta];
}
for(int sta=1;sta<(1ll<<m1);sta++)
{
int U=(1<<m2)-1,sum=__builtin_popcount(sta);
for(int i=1;i<=m1;i++) if((sta>>i-1)&1) if((e[i]&sta)!=(sta^(1ll<<i-1))) goto Z;
for(int i=1;i<=m1;i++) if((sta>>i-1)&1) U&=e[i]>>m1;
maxn=max(maxn,sum+__builtin_popcount(f[U])); Z:;
}
printf("%.6lf",(1.0*(maxn*(maxn-1)/2))*(1.0*all)/(1.0*maxn)*(1.0*all)/(1.0*maxn));
return 0;
}

NOIP模拟85(多校18)的更多相关文章

  1. NOIP模拟83(多校16)

    前言 CSP之后第一次模拟赛,感觉考的一般. 不得不吐槽多校联测 OJ 上的评测机是真的慢... T1 树上的数 解题思路 感觉自己思维有些固化了,一看题目就感觉是线段树. 考完之后才想起来这玩意直接 ...

  2. Noip模拟80 2021.10.18

    预计得分:5 实际得分:140?????????????? T1 邻面合并 我考场上没切掉的大水题....(证明我旁边的cty切掉了,并觉得很水) 然而贪心拿了六十,离谱,成功做到上一篇博客说的有勇气 ...

  3. Noip模拟43 2021.8.18

    T1 地一体 可以树形$dp$,但考场没写出来,只打了没正确性的贪心水了$30$ 然后讲题的时候B哥讲了如何正确的贪心,喜出望外的学习了一下 不难发现 每次士兵都会直接冲到叶子节点 从深的点再返回到另 ...

  4. NOIP模拟92(多校25)

    前言 所以说这次是 HZOI 多校联测巅峰????(题目,数据过水??) T1 石子合并 解题思路 签到题. 发现我们可以给每个数字附一个正负号,每个数字的贡献就是它本身乘上这个符号. 发现至少应该有 ...

  5. NOIP模拟84(多校17)

    T1 宝藏 解题思路 考场上一眼出 \(nlog^2\) 做法,然后没看见是 1s 3e5 的数据,我竟然以为自己切了?? 考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的 ...

  6. NOIP模拟86(多校19)

    T1 特殊字符串 解题思路 \(f_{i,j}\) 表示前 \(i\) 个字符中结尾为 \(j\) 的最大贡献. 转移枚举当前位置于之前位置结尾的组合加上贡献即可. 对于边界问题,容易发现选择 1 一 ...

  7. NOIP模拟88(多校21)

    前言 对于这套题的总体感觉就是难,然后就是自己很菜... 对于 T1 考试时只会一个最垃圾的背包,考完之后对于思路这一块也不是很顺利,大概这就是薄弱的地方吧. 然后 T2 是比较简单的一道题了,但是考 ...

  8. NOIP模拟96(多校29)

    T1 子集和 解题思路 大概是一个退背包的大白板,然而我考场上想复杂了,竟然还用到了组合数. 但是大概意思是一样的,有数的最小值一定是一个在 \(a\) 数组中存在的数字. 那么我们想办法除去它对应的 ...

  9. NOIP模拟99(多校31)

    T1 法阵 解题思路 原题3100,张口放 T1(出题人原话) 思维题,合法的情况其实就是上下两个梯形拼起来的样子. 他们的边界都是在 \(i\) 轴上面,但是不能相交. 于是我们可以尝试两者相交的纵 ...

随机推荐

  1. golang中的左值VS右值

    对应关系 左值 可寻址 右值 不可寻址 可寻址:可以通过&取地址符,获取内存地址; 可寻址,也就是分配了内存; 不可寻址:根本没有分配内存; 常量const 常量通常只支持数字/字符串/布尔, ...

  2. SpringAOP-动态代理,日志注入

    SpringAOP 前言: 1.AOP定义? 用来干啥的? 怎么用?(怎么跑通它的思路) 代理模式 为啥要学代理模式? -- 因为是SpringAop的底层 原有的代码不敢动,一动就是Bug,.所以使 ...

  3. 【PHP数据结构】栈的相关逻辑操作

    对于逻辑结构来说,我们也是从最简单的开始.堆栈.队列,这两个词对于大部分人都不会陌生,但是,堆和栈其实是两个东西.在面试的时候千万不要被面试官绕晕了.堆是一种树结构,或者说是完全二叉树的结构.而今天, ...

  4. PHP中的对象比较

    在之前的文章中,我们讲过PHP中比较数组的时候发生了什么?.这次,我们来讲讲在对象比较的时候PHP是怎样进行比较的. 首先,我们先根据PHP文档来定义对象比较的方式: 同一个类的实例,比较属性大小,根 ...

  5. Jvm调优理论篇

    Jvm实战调优 OOM(Out Of Memory) 内存溢出错误 ps:由于Java虚拟机有许多实现,本文主要阐述的是OpenJDK的HotSpot虚拟机,JDK版本是8. 一.首先要明白造成OOM ...

  6. Spring Cloud Hystrix 学习(三)请求合并

    什么是请求合并?我们先来看两张图: 上方的两张图中,第二张可以看出服务端只执行了一次响应,这就是请求合并.客户端新增的请求合并模块,内部存在一个等待的时间窗口,将一定时间段内满足条件的请求进行合并,以 ...

  7. html正文提取工具goose的安装及简单使用Demo

    1.git clone https://github.com/grangier/python-goose.git 2.cd python-goose 3.sudo pip install -r req ...

  8. 深入浅出WPF-06.Binding(绑定)02

    Binding对数据的校验和转换 1)数据校验,通过Binding的ValidationRules属性(Collection类型)进行校验.可以设置多个数据校验条件. <Slider Margi ...

  9. 宝塔配置vnc+wine实现Q群机器人

    图形界面必备X Window System yum -y groupinstall "X Window System" 安装epel源 yum -y install epel-re ...

  10. html行内元素

    定义 行内元素只占据它对应标签的边框所包含的空间,没有换行效果 div{ /* 定义行内元素*/ display:inline } 特点 多个元素可以横排显示 不支持宽高和上下margin 支持pad ...