首页 > 其他分享 >6.28 模拟赛小记

6.28 模拟赛小记

时间:2023-07-02 12:55:06浏览次数:27  
标签:return int ll 6.28 ans 区间 mod 模拟 小记

大脑宕机了!错误已更正,感谢提醒!

---

[更好的阅读体验?]()
---

A.木棍切割 1

我现在很难解释我的做法,只能说 n^3 大标之后就很容易推出柿子了。现在还不知道怎么证明正确性qwq

以及如果模拟赛你去洛谷找原,找到的不是这个,是木棍切割 2,如果看看题面的话就不会掉进坑里。

```cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
signed main()
{
scanf("%lld", &n);
if(n & 1) puts("0");
else
{
if(n % 4 == 0) printf("%lld", n / 4 * 6 - 5);
else printf("%lld", (n - 2) / 4 * 6);
}
return 0;
}
```

---

B.第 k 小

用 dp 的思想。f[i][j] 表示前 i 位中 1 的个数最多有 j 个的答案方案数。边界为 ```f[0][i] = 1, f[i][0] = 1;```,此时答案分别为该数字长度为 0、该数字全是 0。

转移方程比较好理解:对于 f[i][j],当 j <= i 时才可能更新答案,考虑这一位选 1 还是选 0,分别对应 f[i - 1][j - 1] 和 f[i - 1][j]。否则答案同 f[i][i]。

接下来需要构造答案,感觉思维上比较有难度。

1.我们需要构造长度为 n 且 1 的个数不超过 m 的第 k 小数。从最高位到最低位枚举长度,**所以当前位选 1 一定大于选 0**。

**2.对于第 k 小,我们需要把这个数从 f[1 ~ n][0 ~ m] 这些所存方案数中拼出来。**

3.若 k > f[i - 1][j] ,我们这一位即使放了 1 也满足不了答案。所以直接放 1,然后把这部分方案从 k 中减掉。

4.若 k < f[i - 1][j] ,那就不能放 1,若放了 1 方案数就超过要求了。

稍微绕了点弯,感觉不好想,但算一种比较典的拼凑思路罢。
```cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n, m, k;
ll f[32][32];
int main()
{
scanf("%d%d%lld", &n, &m, &k);
for(int i = 0; i <= n; i ++ )
{
f[i][0] = 1;
f[0][i] = 1;
}
for(int i = 1; i <= n; i ++ )
{
for(int j = 1; j <= n; j ++ )
{
if(j <= i) f[i][j] = f[i - 1][j - 1] + f[i - 1][j];
else f[i][j] = f[i][i];
}
}
int i = n, j = m;
while(i)
{
if(k > f[i - 1][j] && k)
{
printf("1");
k -= f[i - 1][j];
j --;
}
else printf("0");
i --;
}
return 0;
}
```

感觉本题非常聪明,我叹为观止,大受震撼。是我太愚笨了。但模拟赛本题纯暴力枚举 k 就能拿到 70pts 感觉非常有实力。赛时写了不严格 O(n) 枚举,但显然 K 巨大所以炸了是情理之中。但暴力能有这么多分是我没想到的。

---

C.蚂蚁掉头

又是很精妙的题,愈发显得我像一个脑瘫的很棒的题。

考虑数形结合。在数轴上,向右走是向右上走,向左走是向右下。

我们以 $N = 2$ 时来举例。那么画出来的图大概会长这个样子。

![](https://cdn.luogu.com.cn/upload/image_hosting/gubrcxif.png)

蓝色线将它们分成两层,分别表示两个小区间。黄色表示路径,而粉色圈出来的“尖”是转折点,表示蚂蚁掉一次头。既然我们要求最小的调头次数,那就要最少的“尖”。

通过手动枚举(你自己画画图试试),我们发现这两层中,上一层的尖的个数、下一层承接尖的“台”个数都固定。因此确定方案数,就是确定哪个尖放在哪个台上。(注意,尖和台的样子都固定,所以个体之间没有差异;一个台可以放多个尖,也可以有台空着不放,自己形成一个下层尖。)尖、台的个数是 a[i] / 2。

可以类比将 n 个苹果放到 m 个篮子里。

1.$n > m$:为了不产生新的“尖”,那就让每个台上都至少放一个尖。根据插板法,将尖分成 m 块,即在尖之间 n - 1 个空里放 m - 1 个插板。$$ ans = ans * {C_{a[i + 1] - 1}^{a[i] - 1}}$$

2.$n <= m$:为了不让台产生(下面一层)新的“尖”,那就让每个台上都尽量有尖。即在 m 个位置里选 n 个。
$ans = ans * C_{a[i]}^{a[i+1]}$

这里只是两层。同理,如果扩展到多层,可以把“台”看成新的“尖”,与下面的“台”再进行配对。每层之间的选择互不影响,所以根据乘法原理把它们都乘起来就是总方案数。

![](https://cdn.luogu.com.cn/upload/image_hosting/jz17phom.png)

至于乘的过程中可能会出现 0,那就把 jc[0] 设为 1即可。

```cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e6 + 10;
const int mod = 1e9 + 7;
int n;
int a[N];
ll jc[N];
ll pmod(ll a, ll b)
{
ll tot = 1;
while(b)
{
if(b & 1) tot = (tot * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return tot % mod;
}
ll C(ll x, ll y)
{
return jc[x] * pmod(jc[y], mod - 2) % mod * pmod(jc[x - y], mod - 2) % mod;
}
int main()
{
ll ans = 1;
scanf("%d", &n);
for(int i = 1; i <= n; i ++ )
{
scanf("%d", &a[i]);
if(a[i] & 1)
{
cout << "0";
return 0;
}
a[i] /= 2;
}
jc[0] = 1;
for(int i = 1; i <= 1000000; i ++ ) jc[i] = (jc[i - 1] % mod * i % mod) % mod;
for(int i = 1; i < n; i ++ )
{
if(a[i + 1] > a[i]) ans = (ans * C(a[i + 1] - 1, a[i] - 1)) % mod;
else ans = (ans * C(a[i], a[i + 1])) % mod;
}
printf("%lld", ans);
return 0;
}
```

---

D.区间

不好评价,爆锤我自己,赛时读不懂题,理解能力为 0。

用 dp 的思想,把每个区间按照左端点从小到大排序(方便后面前缀和统计),然后将区间一个个加入,依次统计答案。另 f[i] 表示选了 i 个区间时的总价值。

在状态转移时,f[i] 的取值来自两部分:一是前 i - 1 个区间子集产生的价值,这个不会因为加入新区间而改变;另一部分是来自于前 i - 1 个区间中和第 i 个区间没有交集的区间,它们的价值分别会加 1。设 x 表示和当前区间不相交的区间个数,由集合的性质得到这样的子集共有 $2^x$ 个。

于是得到 $f[i] = f[i - 1] + (f[i - 1] + 2^x)$。

接下来就是求 x。设当前区间为 i,与其不相交的区间为 j,则 $a[i].r < a[j].l$。于是我们统计一遍区间的所有右端点,对于每个位置进行一个前缀和表示这个位置之前有多少个区间,于是 $x = s[a[i].l - 1]$。这也是为什么要按照左端点排序。

```cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int n;
int ans;
int f[N], sum[N];
struct node{int l, r;}a[N];
bool cmp(node x, node y){return x.l < y.l;}
int bpow(int a, int b)
{
int ans = 1;
while(b)
{
if(b & 1) ans = (ans * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return ans;
}
signed main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++ )
{
scanf("%d%d", &a[i].l, &a[i].r);
s[a[i].r] ++;
}
for(int i = 1; i <= n * 2; i ++ ) s[i] += s[i - 1];
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; i ++ ) f[i] = (f[i - 1] * 2 % mod + bpow(2, s[a[i].l - 1])) % mod;
printf("%d", f[n]);
return 0;
}
```

标签:return,int,ll,6.28,ans,区间,mod,模拟,小记
From: https://www.cnblogs.com/Moyyer-suiy/p/17520660.html

相关文章

  • LINQ问题:模拟并发冲突时遇到的问题(LINQ to SQL)
    问题描述此问题是通过的网友交流获得解决的,首先对参与和关注此问题的网友表示感谢,特别是foren_whb给予了热心地、直接地帮助!谢谢你们!望日后继续进行着广泛地深入的交流!虽然说,谁也不想遇到并发冲突这种情况,但这却是一个必然会发生的事情,因此,学习掌握它的解决办法还是很有必要的。我......
  • 2023冲刺国赛模拟 28.1
    T3函数首先存在结论\(f(a+2C)=f(a)+2C\)。简单证明,设\(b=2f(a)-a+1\),那么\(f(b)=f(a)+C\),设\(d=2f(b)-b+1\),那么\(f(d)=f(a)+2C\),同时:\[\begin{aligned}d&=2f(b)-b+1\\&=2f(a)+2C-2f(a)+a-1+1\\&=a+2C\end{aligned}\]根据结论可以知道,我们可以将函数\(f......
  • assert断言与const修饰指针的妙用(模拟实现strcpy函数)
     assert断言目录assert断言的妙用:头文件:使用方法:const修饰指针的妙用主要用法const在*左边const在*右边断言和const修饰指针的应用模拟实现C语言strcpy函数  1、若字符串str1,str2有空指针怎么办?  2.str2改变了怎么办?assert断言的妙用:头文件:#include<assert.h>使用方法:当......
  • 冲刺国赛模拟 28
    一天两个小时踹了两回机箱还把我五道题题解踹没了,我不好说什么。论坛数学版看到一道高消dp的题,第一反应是这是个马尔可夫链可以列矩阵求逆嗯解。我是不是魔怔了。\[%>特别是当两者科技树点的都很歪而且歪的方向不同的时候。——H_Kaguyain13.5%你在影射什么我不好说。\]k......
  • 狂收 3.2k star!百度开源压测工具,可模拟几十亿的并发场景,太强悍了!
    dperf是一款基于DPDK的100Gbps网络性能和负载测试软件,能够每秒建立千万级的HTTP连接、亿级别的并发请求和数百Gbps的吞吐量。优点性能强大:基于DPDK,使用一台普通x86服务器就可以产生巨大的流量:千万级的HTTP每秒新建连接数,数百Gbps的带宽,几十亿的并发连接数统......
  • 2023冲刺国赛模拟 27.1
    话说我的习惯是一套题全部改完后才写题解,然而上次的题解停留在\(20.1\),这足以看出近两日的颓废现状。由于昨天晚上做了个噩梦,所以今天的题解先扯点别的。目前初步鉴定噩梦是由FateZero中Caster的行为引起的。比较显然Caster及其御主都是以他人的痛苦为乐的人。在现代......
  • matlab仿真逆变器故障模拟 牵引逆变器IGBT故障模拟系统
    matlab仿真逆变器故障模拟牵引逆变器IGBT故障模拟系统原创文章,转载请说明出处,资料来源:http://imgcs.cn/5c/629480936977.html......
  • 风电光伏的场景生成与消减-matlab代码 可利用蒙特卡洛模拟或者拉丁超立方生成光伏和
    风电光伏的场景生成与消减-matlab代码可利用蒙特卡洛模拟或者拉丁超立方生成光伏和风电出力场景,并采用快速前推法或同步回代消除法进行削减,可以对生成场景数和削减数据进行修改,下图展示的为1000个场景削减至10个典型场景,并获得各场景概率。这段程序主要是使用拉丁差立方抽样方法......
  • Vue3+Element-Plus安装及模拟增删改查
    软件安装:nodejs16https://nodejs.org/download/release/v16.20.0/将npm设置为淘宝镜像:npmconfigsetregistryhttps://registry.npm.taobao.org 创建vue3项目:npminitvue@latestEleement-Plushttps://element-plus.gitee.io/zh-CN/安装:npminstallelement-......
  • 模拟费用流
    看到cmd的博客之后对模拟费用流有了新的理解。模拟费用流,实际上是对于某些特殊的费用流建模模拟跑费用流的过程,复杂度比直接跑费用流要低许多。首先费用流是个凸函数,因为根据EK,增广路长度不断增长,则费用是关于流量的凸函数。然后是模拟费用流通常解决的问题:最小/大费用任......