NOIP 膜你题 DAY2
NOIp膜你题 Day2
duliu 出题人:ZAY
题解
这就是一道组合数问题鸭!!! 可是泥为什么没有推出式子!!
首先我们知道的是 m 盆花都要摆上,然后他们的顺序不定(主人公忘记了)
所以初步得到一个排列数 P( m,m ) , 即 Pmm
那么我们就还剩下 n-m 个空位置,这些空位置都是不可以放花的,于是我们逆向思维一下:
n-m 个位置不放花,也就是可以在这些位置周围插空放花,把这些位置隔开,那么就可以把m盆花放到 n-m+1 个空里,由于这是对于空位置来说的,没有顺序可言,每个都是一毛一样的,所以得到一个组合数 C(n-m+1 , m) , 即 Cn-m+1m
所以 ans = P( m,m ) * C( n-m+1 , m )
= m! * (n-m+1)! / [ m! * (n-m+1 - m)! ]
化简一下就是下面
=(n-m+1)*(n-m+1-1)*......*(n-2m+2)
注意
ans 要开 long long , 试过毒了,数据不开 long long 会炸
代码
#include<bits/stdc++.h> using namespace std; int type,n,m,p;
long long ans=; int main()
{
freopen("ilove.in","r",stdin);
freopen("ilove.out","w",stdout); scanf("%d%d%d%d",&type,&n,&m,&p); if(n==&&m==) { printf("1\n"); return ; } int a=n-m+,b=n-m-m+;
for(int i=a;i>=b;i--)
ans=(ans%p*i%p)%p; printf("%ld\n",ans);
return ; }
看看出题人的题解
一般这种数数题,也就是求方案数,有两种解决方案:DP&组合数学
1.DP
2.组合数学
Ps:插空法就是我上面题解里面提到的
题解
注意到根据题目规定的走法,在进入一个节点以后,必须遍历完它的整个子树, 否则一旦离开这个节点,再也无法进入这棵子树,从而导致该节点的某个孩子没能放 上石子,导致这个节点不能放上石子。
同时又有每个节点放上石子以后,它的子树的 石子可以全部取回。设在节点 u 放石子需要有 ansu 个石子,则放完 u 以后可以取回 ansu-wu 个石子。
因为你准备了ansu个石子,u点需要wu个石子放上,那么放完之后,他的子树上的石子就可以取回来了,也就是ansu-wu个,这些也就是节点u的孩子所需石子数和。
于是考虑影响问题答案的显然是从 u 进入每个孩子的顺序,由于最多有两个孩 子,直接比较一下就可以知道先进入哪个孩子更优秀了。时间复杂度 O(n)
代码
#include <cstdio>
#include <vector>
#include <algorithm> const int maxn = ; int n;
int MU[maxn], ans[maxn]; //MU也就是W
std::vector<int>son[maxn]; void dfs(const int u);
bool cmp(const int &_a, const int &_b); int main() {
freopen("yin.in", "r", stdin);
freopen("yin.out", "w", stdout); scanf("%d", &n);
for (int i = , x; i <= n; ++i) {
scanf("%d", &x);
son[x].push_back(i);
}
for (int i = ; i <= n; ++i) {
scanf("%d", MU + i);
//数组名+一个东西 这是指针的写法
//相当于scanf("%d",&MU[i]);
}
dfs();
for (int i = ; i < n; ++i) {
printf("%d ", ans[i]);
}
printf("%d\n", ans[n]);
return ;
} void dfs(const int u) {
for (auto v : son[u]) { //遍历u的所有子节点
dfs(v);
}
std::sort(son[u].begin(), son[u].end(), cmp);
//按照差值不升序排序
int _ret = ;
//此时U节点的所有子节点已经算出来了,准备计算U节点
for (auto v : son[u]) { //叶节点没有儿子就不会for循环
if (_ret >= ans[v]) //上一个子节点收回的石子足够摆当前节点,就摆上
{
_ret -= ans[v]; //ret摆完之后更新
}
else
{
ans[u] += ans[v] - _ret; //收回的石子不够放了,往上补
_ret = ans[v] - MU[v];
//遍历完U的儿子V节点对应的子树后,收回除了 U的儿子v以外所有节点上的石头
}
}
ans[u] += std::max(, MU[u] - _ret);
//深搜,会先到达所有叶节点,并且所有叶节点的ans=w[i]
} inline bool cmp(const int &_a, const int &_b) {
return (ans[_a] - MU[_a]) > (ans[_b] - MU[_b]);
}
题解
1.可以通过前4个任务点的代码QWQ
因为我们看到每封信最多只会有30个字符对吧,那么每次询问给出一个询问区间的时候,我们就可以比对每一位的字符
比如我们比对到了第 i 位,询问区间从头到尾枚举看一看,对于这一位,有几个0,几个1,几个?
如果既有0又有1,那么显然是无解的
如果只有0和?,那么这一位只可以为0,也就是?只能被填成0
如果只有1和?,同上
如果全是?,那么既可以填0,又可以填1,也就是有2种方案
我们把所有位都枚举了一遍,那么可能会出现结果:无解,有唯一解,有解但不唯一;对于最后一种情况显然是?的数目影响的,乘法分布原理 2cnt , cnt表示?的数目
代码
45‘代码 后边超时辣
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath> using namespace std; string s[],s1;
int n,m,q;
int qus,num,l,r;
long long ans=; int main()
{
freopen("lin.in","r",stdin);
freopen("lin.out","w",stdout);
scanf("%d%d%d",&n,&m,&q); if(q==) return ; for(int i=;i<=m;i++)
cin>>s[i]; for(int i=;i<=q;i++)
{
ans=;
scanf("%d",&qus);
if(qus==)
{
scanf("%d%d",&l,&r); int flag=,cnt=; for(int j=;j<n;j++)
{
if(flag==) break;
bool glf=;
char mp;
mp=s[l][j];
if(mp!='?') glf=;
else glf=;
for(int k=l+;k<=r;k++)
{
if(s[k][j]!='?')
{
if(mp=='?')
{
glf=;
mp=s[k][j];
continue;
}
if(mp!='?'&&mp!=s[k][j])
{
flag=;
continue;
} } else if(s[k][j]=='?')
{
if(glf==) glf=;
} }
if(mp!='?') glf=;
cnt+=glf;
} if(flag==) {printf("0\n");}
else
{
ans=pow(,cnt);
printf("%ld\n",ans); }
}
if(qus==)
{
scanf("%d",&num);
cin>>s1;
s[num]=s1;
}
} return ;
}
我百分之200的错误都是因为脑残,下面这个是整理了一下(貌似并不可以多得分)
#include<bits/stdc++.h> using namespace std; int n,m,q;
string s[],s1;
int opt,l,r,pos; inline int read()
{
int ans=;
char last=' ',ch=getchar();
while(ch<''||ch>'') last=ch,ch=getchar();
while(ch>=''&&ch<='') ans=ans*+ch-'',ch=getchar();
if(last=='-') ans=-ans;
return ans;
} int main()
{
freopen("lin.in","r",stdin);
freopen("lin.out","w",stdout); n=read(); m=read(); q=read();
for(int i=;i<=m;i++)
cin>>s[i]; for(int i=;i<=q;i++)
{
opt=read();
if(opt==)
{
pos=read();
cin>>s1;
s[pos]=s1;
}
else
{
l=read();r=read(); long long ans;
int flag=,cnt=; for(int j=;j<n;j++)
{
if(flag==) break;
int flag0=,flag1=,flag2=;
for(int k=l;k<=r;k++)
{
if(s[k][j]=='') flag0++;
if(s[k][j]=='') flag1++;
if(s[k][j]=='?') flag2++;
} if(flag0!=&&flag1!=) { flag=; continue; }
else if(flag2==(r-l+)) cnt++; } if(flag==) ans=;
else ans=pow(,cnt);
printf("%ld\n",ans); }
} return ;
}
当然也可以用按位与维护
2.考虑正解:线段树
代码
忍不了这个指针了
#include <cstdio> template <typename T> inline void qr(T &x) {
char ch = getchar(), lst = ' ';
while ((ch > '') || (ch < '')) lst = ch, ch=getchar();
while ((ch >= '') && (ch <= '')) x = (x << ) + (x << ) + (ch ^ ), ch = getchar();
if (lst == '-') x = -x;
} //快读 const int maxn = ; int n, m, q;
char s[maxn][]; //每封信的内容 #ifdef ONLINE_JUDGE
int Ans;
#endif struct Tree {
Tree *ls, *rs;
int l, r, x, y;
bool leg; //是否合法 Tree() {
ls = rs = NULL;
l = r = x = y = ;
leg = true; //先假定合法
} void pushup() { //构造a1,a2,b1,b2
if (!(this->ls->leg && this->rs->leg)) {
this->leg = false;
} else {
if ((this->ls->x & this->rs->x) & (this->ls->y ^ this->rs->y)) {
this->leg = false;
} else {
this->leg = true;
this->x = this->ls->x | this->rs->x;
this->y = this->ls->y | this->rs->y;
}
}
}
};
Tree *rot; //线段树的根 void ReadStr(char *p); //指针 快读
void Update(const int x);
void Query(const int l, const int r);
void update(Tree *const u, const int p); //修改
Tree query(Tree *u, const int l, const int r); //查询
void build(Tree *const u, const int l, const int r); //建树 int main() {
freopen("lin.in", "r", stdin);
freopen("lin.out", "w", stdout);
qr(n); qr(m); qr(q);
for (int i = ; i <= m; ++i) {
ReadStr(s[i] + );
}
build(rot = new Tree, , m); //建树
int opt, l, r;
while (q--) {
opt = ; qr(opt);
if (opt == ) { //查询
l = r = ; qr(l); qr(r);
Query(l, r);
} else {
l = ; qr(l);
ReadStr(s[] + );
Update(l); //修改第一个
}
}
#ifdef ONLINE_JUDGE //鬼知道干啥的
printf("%d\n", Ans);
#endif
return ;
} void ReadStr(char *p) {
do *p = getchar(); while ((*p != '') && (*p != '') && (*p != '?'));
do *(++p) = getchar(); while ((*p == '') || (*p == '') || (*p == '?'));
*p = ;
} void build(Tree *const u, const int l, const int r) {
if ((u->l = l) == (u->r = r)) { //当前区间在要建的区间内
for (int i = ; i <= n; ++i) {
if (s[l][i] != '?') {
u->x |= << i;
if (s[l][i] == '') {
u->y |= << i;
}
}
}
} else { //不在
int mid = (l + r) >> ;
build(u->ls = new Tree, l, mid);
build(u->rs = new Tree, mid + , r);
u->pushup();
}
} Tree query(Tree *u, const int l, const int r) {
if ((u->l > r) || (u->r < l)) return Tree(); //当前区间完全不在查询区间
if ((u->l >= l) && (u->r <= r)) return *u; //完全在
Tree _ret;
auto ll = query(u->ls, l, r), rr = query(u->rs, l, r); //否则递归来求
_ret.ls = ≪ _ret.rs = &rr;
_ret.pushup();
return _ret;
} void Query(const int l, const int r) {
auto _ret = query(rot, l, r);
if (!_ret.leg) { //不合法输出‘0’
#ifndef ONLINE_JUDGE
puts("");
#endif
} else {
int ans = ;
for (int i = ; i <= n; ++i) if (!(_ret.x & ( << i))) {
ans <<= ;
}
#ifdef ONLINE_JUDGE
Ans ^= ans;
#else
printf("%d\n", ans);
#endif
}
} void update(Tree *u, const int p) { //修改第p个
if (u->ls) { //寻找p
if (u->ls->r >= p) { //左子树右端点比p大
update(u->ls, p);
} else {
update(u->rs, p);
}
u->pushup(); //把子节点的信息合并到父节点
} else {
*u = Tree();
u->l = u->r = p;
for (int i = ; i <= n; ++i) {
if (s[][i] != '?') {
u->x |= << i;
if (s[][i] == '') {
u->y |= << i;
}
}
}
}
} void Update(const int x) {
update(rot, x); //修改
}
拒绝理解Zay的代码
放一只water lift的代码(线段树板子)
#include <bits/stdc++.h>
using namespace std;
template <class T>
inline void read(T &num)
{
bool flag = ;
num = ;
char c = getchar();
while ((c < '' || c > '') && c != '-')
c = getchar();
if (c == '-')
{
flag = ;
c = getchar();
}
num = c - '';
c = getchar();
while (c >= '' && c <= '')
num = (num << ) + (num << ) + c - '', c = getchar();
if (flag)
num *= -;
}
template <class T>
inline void output(T num)
{
if (num < )
{
putchar('-');
num = -num;
}
if (num >= )
output(num / );
putchar(num % + '');
}
template <class T>
inline void outln(T num)
{
output(num);
putchar('\n');
}
template <class T>
inline void outps(T num)
{
output(num);
putchar(' ');
}
const int N = , M = ;
int n, m, q;
struct segment
{
char val[M];
bool all1[M * ];
bool all0[M * ];
void init(int node, int nl, int nr)//这是个正常的线段树的板子(虽然位置好像不大正常)
{
if (nl < nr)
{
int mid = (nl + nr) >> ;
init(node * , nl, mid);
init(node * + , mid + , nr);
all1[node] = all1[node * ] & all1[node * + ];
all0[node] = all0[node * ] & all0[node * + ];
}
else
{
if (val[nl] == '?')
all1[node] = all0[node] = ;
else
{
all1[node] = val[nl] == '';
all0[node] = val[nl] == '';
}
}
}
void modify(int node, int nl, int nr, int x, char va)
{
if (val[x] == va)
return;
if (nl < nr)
{
int mid = (nl + nr) >> ;
if (x <= mid)
{
modify(node * , nl, mid, x, va);
}
else
{
modify(node * + , mid + , nr, x, va);
}
all1[node] = all1[node * ] & all1[node * + ];
all0[node] = all0[node * ] & all0[node * + ];
}
else
{
if (va == '?')
all1[node] = all0[node] = ;
else
{
all1[node] = va == '';
all0[node] = va == '';
}
val[x] = va;
}
}
pair<bool, bool> query(int node, int nl, int nr, int l, int r)
{
if (l <= nl && r >= nr)
{
return make_pair(all1[node], all0[node]);
}
int mid = (nl + nr) >> ;
bool a1 = true, a0 = true;
if (l <= mid)
{
auto lo = query(node * , nl, mid, l, r);
a1 &= lo.first;
a0 &= lo.second;
}
if (r >= mid + )
{
auto lo = query(node * + , mid + , nr, l, r);
a1 &= lo.first;
a0 &= lo.second;
}
return make_pair(a1, a0);
}
void dfs(int node, int nl, int nr)
{
if (nl < nr)
{
int mid = (nl + nr) >> ;
dfs(node * , nl, mid);
dfs(node * + , mid + , nr);
}
outps(nl);
outps(nr);
outps(all1[node]);
outln(all0[node]);
}
} segs[N];
int main()
{
freopen("lin.in", "r", stdin);
freopen("lin.out", "w", stdout);
read(n);
read(m);
read(q);
char ch;
for (int i = ; i <= m; i++)
{
for (int j = ; j <= n; j++)
{
do
{
ch = getchar();
} while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\0');
segs[j].val[i] = ch;
}
}
for (int i = ; i <= n; i++)
{
segs[i].init(, , m);
}
while (q--)
{
bool opt;
read(opt);
if (opt == )
{
int l, r;
read(l);
read(r);
int ans = ;
for (int i = ; i <= n; i++)
{
auto lo = segs[i].query(, , m, l, r);
ans *= (lo.first + lo.second);
}
outln(ans);
}
else
{
int pos;
read(pos);
for (int i = ; i <= n; i++)
{
do
{
ch = getchar();
} while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\0');
segs[i].modify(, , m, pos, ch);
}
}
}
}
彩蛋:
考试暴露了很多小问题
1.文件的读写
安利一个方法:如何比较自己的代码ans和答案out是否一致(不仅是用在NOIP上,还有NOI,IOI)
(1)键盘按住 shift 键,同时鼠标右键单击
(2)会崩出一个会话框,点击“在此处打开命令窗口”,win10不大一样,好像是f**忘了
(3)就会出现这个东西
不输入cmd 也可以,因为它本身就是cmd
(4)输入 fc 文件1 文件2
如果不同的话
如果相同的话
这样你就可以看看自己的答案对不对,错在哪里QWQ
2.数据分治
也就是对于不同的子任务你可以用不同的方法解决掉,从而骗取更多分数
3.编译&加文件的顺序
大型考试的时候呢,如果你代码一旦进行了修改,那么一定要重新试一遍样例
freopen就不要注释掉啦
4.题目难度和顺序安排不一定有瓜
NOIP 膜你题 DAY2的更多相关文章
- NIOP 膜你题
NOIp膜你题 Day1 duliu 出题人:ZAY 1.大美江湖(mzq.cpp/c) [题目背景] 细雪飘落长街,枫叶红透又一年不只为故友流连,其实我也恋长安听门外足音慢,依稀见旧时容颜 ...
- NOIp 2015真题模拟赛 By cellur925
果然我还是最菜的==不接受反驳== Day1 T1:神奇的幻方 思路:直接模拟即可,由于当前放法只与上一放法有关系,用两个变量记录一下即可.10分钟内切掉== 预计得分:100分 实际得分:100分 ...
- [NOIP 2014复习]第三章:动态规划——NOIP历届真题回想
背包型动态规划 1.Wikioi 1047 邮票面值设计 题目描写叙述 Description 给定一个信封,最多仅仅同意粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定全部的邮票数量都 ...
- NOIP提高真题整理(2011-2018)-标签
加粗的后面应该会有相应的简单解析(如果没咕的话:)). 2011 day1 T1:铺地毯:逆着铺 T2:选择客栈:按颜色分类枚举+二分答案 T3:Mayan游戏:大模拟dfs+剪枝 day2 T1:计 ...
- Noip 2013 真题练习
Day1 T1 转圈游戏 Link 一句话题意: 让你求 \({x + m \times 10^k} \bmod n\) 的结果. 直接套上快速幂的板子. code #include<iostr ...
- 备战NOIP每周写题记录(一)···不间断更新
※Recorded By ksq2013 //其实这段时间写的题远远大于这篇博文中的内容,只不过那些数以百记的基础题目实在没必要写在blog上; ※week one 2016.7.18 Monday ...
- 【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】
比较好想的一道题,直接用队列滑窗,因为扫一遍往队列里加东西时,改变的只有一个值,开桶储存好就行了! #include<bits/stdc++.h> using namespace std; ...
- 2017北京国庆刷题Day2 afternoon
期望得分:100+100+50=250 实际得分:100+70+50=220 T1 最大值(max) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一 ...
- 2017北京国庆刷题Day2 morning
期望得分:100+100+40=240 实际得分:100+40+0=140 T1 一道图论神题(god) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK ...
随机推荐
- Codeforces 892C/D
C. Pride 传送门:http://codeforces.com/contest/892/problem/C 本题是一个关于序列的数学问题——最大公约数(GCD). 对于一个长度为n的序列A={a ...
- 【Mail.Ru Cup 2018 Round 2 C】 Lucky Days
[链接] 我是链接,点我呀:) [题意] [题解] 题解的作者: manish_joshi 对于任意一个k 因为那条直线(关于x,y的方程可以看出一条直线)的斜率>= 所以肯定会经过第一象限. ...
- firefox历史版本下载地址
http://ftp.mozilla.org/pub/firefox/releases/
- 0809MySQL实战系列:大字段如何优化|数据存储结构
转自https://yq.aliyun.com/articles/59256?spm=5176.100239.blogcont59257.9.5MLR2d 摘要: 背景 线上发现一张表,1亿的数据量, ...
- D 分组背包
<span style="color:#3333ff;">/* ---------------------------------------------------- ...
- 自己定义UISlider的样式和滑块
//自己定义UISlider的样式和滑块 //轨道图片 UIImage *stetchLeftTrack = [UIImage imageNamed:@"thick"]; UIIm ...
- 扩展欧几里德 poj1061 青蛙的约会
扩展欧几里德很经典.可是也有时候挺难用的.一些东西一下子想不明确.. 于是来了一个逆天模板..仅仅要能列出Ax+By=C.就能解出x>=bound的一组解了~ LL exgcd(LL a, LL ...
- Windows下Go语言 幽灵蛛的配置
这里是环境变量 目录结构 在这其中,我主要需要观察src
- Working with SQL Server LocalDB
https://docs.asp.net/en/latest/tutorials/first-mvc-app/working-with-sql.html The ApplicationDbContex ...
- 微阅读,不依赖playground,打包成H5版本--案例学习
微阅读,不依赖playground,打包成H5版本 https://github.com/vczero/weex-yy-h5