前言

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

然后我只知道 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. 74cms v3.3 后台SQL注入

    注入存在于后台 admin_baiduxml.php 代码 52-63行 elseif($act == 'setsave') { $_POST['xmlmax']=intval($_POST['xml ...

  2. clion结合vcpkg以及GTest的使用

    目录 一.vcpkg简介.下载和使用 1. vcpkg是什么 2. vcpkg下载 3. 使用vcpkg下载第三方库 二.clion结合vcpkg 1. 方法一:使用环境变量 2. 方法二:添加cma ...

  3. [Linux系列]DNS系列理论笔记与DNS服务器配置

    0x01 基础术语 DNS(Domain Name System,域名系统),域名和IP地址相互映射的一个分布式数据库,简而言之就是通过更易记忆的域名代替IP去访问一个网站. FQDN(Fully Q ...

  4. 删除数组中指定的元素,然后将后面的元素向前移动一位,将最后一位设置为NULL 。 String[] strs={“aaa”,”ccc”,”ddd”,”eee”,”fff”,”ggg”}; 指定删除字符串“ccc”,把后的元素依次向前移动!!!

    public static void main(String[] args) { int temp = -1; String[] strs = {"aaa", "ccc& ...

  5. 自定义cs程序安装界面

    http://www.crifan.com/achieve_fixed_install_path_while_install_software_when_make_msi_installer/ 制作C ...

  6. STM32F103C8T6使用SPI接口驱动WS2812b灯条

    之前一篇文章写了使用IO控制WS2812b操作原理,但是由于IO的输出比较慢,所以现在改用了硬件SPI控制WS2812b灯条 把SPI的mosi线接到ws2812b的数据线,SPI的速率可达十几Mbi ...

  7. java线程day-02

    1.什么是线程 * 线程是程序执行的一条路径, 一个进程中可以包含多条线程 * 多线程并发执行可以提高程序的效率, 可以同时完成多项工作 2.多线程的应用场景 * 红蜘蛛同时共享屏幕给多个电脑 * 迅 ...

  8. 【PHP数据结构】完全二叉树、线索二叉树及树的顺序存储结构

    在上篇文章中,我们学习了二叉树的基本链式结构以及建树和遍历相关的操作.今天我们学习的则是一些二叉树相关的概念以及二叉树的一种变形形式. 完全二叉树 什么叫完全二叉树呢?在说到完全二叉树之前,我们先说另 ...

  9. PHP的Mhash扩展函数的学习

    这次我们要学习的又是一个 Hash 加密扩展.不过这个扩展 Mhash 已经集成在了 Hash 扩展中.同时也需要注意的是,这个扩展已经不推荐使用了,我们应该直接使用 Hash 扩展中的函数来进行 H ...

  10. TP6 前一个项目可以,第二个项目配置多域名绑定应用一直失效

    之前的域名类似: www.a.com     test.a.com    edu.a.com   ... 文件config/app.php中 'domain_bind' => [ 'test' ...