NOIP模拟13「工业题·卡常题·玄学题」
T1:工业题
基本思路
这题有一个重要的小转化:
我们将原来的函数看作一个矩阵,\(f(i,j-1)*a\)相当于从\(j-1\)向右走一步并贡献a,\(f(i-1,j)*b\)相当于从\(i-1\)向下走一步并贡献b
那么问题就转化成了求从第\(0\)行与第\(0\)列的所有点走到点\((m,n)\)的所有方案数的总贡献
在一个点,对于他之前的点的所有走法,他都有可能向下或右走并带来贡献,所以是统计所有方案数。
易知从点\((i,j)\)到点\((m,n)\)的走的步数是\(m-i+n-j)\),又由于在每一个点都有向下或向右走的可能,我们可以只关注向下(或向右),看每一步向下(或向右)走发生在哪个点,那么方案数就是\(C_{n+m-i}^{n-i}\)(从第0列出发)及\(C_{n+m-i}^{m-i}\)(从第0行出发)
你这么打了,然后你WA了。。。。。。
为什么?
注意:这里的C考虑的是决策点,但是,第0行(列)的点一定会向下(右)走,是不会有决策的,因而正确的式子是:
\]
上代码:
#include<bits/stdc++.h>
using namespace std;
namespace STD
{
#define ll long long
#define rr register
const int SIZE=3e5+4;
const int mod=998244353;
int n,m;
ll a,b,ans;
ll jc[SIZE<<1],inv[SIZE<<1];
ll fn[SIZE],fm[SIZE];
ll b_,a_;
ll qpow(ll base,ll exp)
{
rr ll ret=1ll;
while(exp)
{
if(exp&1) ret=ret*base%mod;
base=base*base%mod;
exp>>=1ll;
}
return ret;
}
inline ll C(ll x,ll y){return jc[x]*inv[y]%mod*inv[x-y]%mod;}
ll read1()
{
rr ll x_read=0ll,y_read=1ll;
rr char c_read=getchar();
while(c_read<'0'||c_read>'9')
{
if(c_read=='-') y_read=-1;
c_read=getchar();
}
while(c_read<='9'&&c_read>='0')
{
x_read=x_read*10+(c_read^48);
c_read=getchar();
}
return x_read*y_read;
}
int read2()
{
rr int x_read=0ll,y_read=1ll;
rr char c_read=getchar();
while(c_read<'0'||c_read>'9')
{
if(c_read=='-') y_read=-1;
c_read=getchar();
}
while(c_read<='9'&&c_read>='0')
{
x_read=x_read*10+(c_read^48);
c_read=getchar();
}
return x_read*y_read;
}
};
using namespace STD;
int main()
{
n=read2(),m=read2(),a=read1(),b=read1();
a%=mod,b%=mod;
a_=qpow(a,m);
b_=qpow(b,n);
//由于后面a^m与b^n会大量用到,所以预处理
for(rr int i=1;i<=n;i++){fn[i]=read1();fn[i]%=mod;}
for(rr int i=1;i<=m;i++){fm[i]=read1();fm[i]%=mod;}
jc[0]=inv[0]=1ll;
for(rr int i=1;i<=n+m;i++){jc[i]=1ll*i*jc[i-1]%mod;inv[i]=qpow(jc[i],mod-2);}
for(rr int i=1;i<=n;i++)
ans=(ans+fn[i]*C(n+m-i-1,m-1)%mod*qpow(b,n-i)%mod*a_%mod)%mod;
for(rr int i=1;i<=m;i++)
ans=(ans+fm[i]*C(n+m-i-1,n-1)%mod*b_%mod*qpow(a,m-i)%mod)%mod;
int x=printf("%lld",ans);
}
T2:
基本思路:
考场上想的普通DP,不对。
实际上是树形DP
实际上可以将Y方点看作边,然后将X方点看作点,\(n\)个点\(n\)条边,很明显,去掉一条边后就是树,我们的任务就是求能将所有的边都覆盖的最小代价,一条边被覆盖是指它的两个端点至少有一个被选。
我们可以判出环来然后删去环里的任一条边,然后以删掉的边的端点跑DP即可
很明显树形DP,DP式就不写在这了,自己推吧,推不出来就自己上代码里找吧。
状态数组\(c[i][j](j=0,1)\)表示i被选(j=1)或不被选(j=0)是以他为根的子树的最小代价。
注意被删掉的边也要被覆盖,所以要在两个端点被选的情况里取min
代码:
#include<bits/stdc++.h>
using namespace std;
namespace STD
{
#define ll long long
#define rr register
#define pp pair<int,int>
#define fi first
#define se second
#define min(x,y) (x<y?x:y)
#define inf LONG_LONG_MAX
#define IT set<int>::iterator
const int SIZE=1e6+4;
int n,root;
ll ans=inf,a,b;
set<int> to[SIZE];
ll val[SIZE];
ll c[SIZE][2];
bool vis[SIZE];
pp edge;
void dfs(int x,int f)
{
static bool ret=0;
vis[x]=1;
for(IT it=to[x].begin();it!=to[x].end();it++)
{
if(*it==f) continue;
if(vis[*it]){edge.fi=x,edge.se=*it;ret=1;return;}
dfs(*it,x);
if(ret) return;
}
}
void DP(int now,int f)
{
//儿子与父亲必须至少有一个选
for(IT it=to[now].begin();it!=to[now].end();it++)
{
if(*it==f) continue;
DP(*it,now);
c[now][1]+=min(c[*it][0],c[*it][1]);
c[now][0]+=c[*it][1];
//鄙视你的智商,连我都推出来的式子你还推不出来过来看。。。。
}
c[now][1]+=val[now];
}
int read()
{
rr int x_read=0,y_read=1;
rr char c_read=getchar();
while(c_read<'0'||c_read>'9')
{
if(c_read=='-') y_read=-1;
c_read=getchar();
}
while(c_read<='9'&&c_read>='0')
{
x_read=(x_read*10)+(c_read^48);
c_read=getchar();
}
return x_read*y_read;
}
};
using namespace STD;
int main()
{
n=read(),a=read(),b=read();
for(rr int i=1;i<=n;i++)
{
int x1=read(),x2=read();
to[x1].insert(x2),to[x2].insert(x1);
val[x1]+=a,val[x2]+=b;
}
dfs(1,1);
to[edge.fi].erase(edge.se);
to[edge.se].erase(edge.fi);
root=edge.fi;
DP(root,root);
ans=min(c[root][1],ans);
for(rr int i=1;i<=n;i++) c[i][0]=c[i][1]=0;
root=edge.se;
DP(root,root);
ans=min(ans,c[root][1]);
printf("%lld",ans);
}
T3:玄学题
基本思路
当我看到-1的时候就已经想到要判指数的奇偶了,但是不会高效地判。
其实想来也很简单(事后诸葛亮),\(d\)为偶数的情况不决定奇偶,只有奇数的情况才决定,而约数数为奇数只有完全平方数一种情况。
证明:
对于每个数,他本身以及1都是他的约数,这就有两个约数了。
假如一个数能被某个数整除,这个数及得数都是其约数,那么,除了某个数平方是这个数,那么他的约数一定成对存在。
而假如有个数的平方是这个数,那么它的商还是他自己,那么他这一“对”就只有他自己。
这个平方数约数个数为奇数。
假如有\(i=p*x^2\)
要想使\(d(i*j)\)是奇数那么j必须满足\(j=p*y^2\),那么我们只要统计\([1,m]\)内有几个j满足条件即可。
首先我们可以写一个线性筛法求出每个i的p,并记录。
线性筛法:
p[1]=1;
for(rr int i=2;i<=en;i++)
p[i*i]=1;
for(rr int i=2;i<=n;i++)
if(!p[i])
{
p[i]=i;
for(rr int j=2;j<=en;j++)
{
if(j*j*i>n) break;
p[j*j*i]=i;
}
}
然后,就有j的个数
\]
\]
证明:
平方在[1,m]范围内的数最多有\(\sqrt{m}\)个那么平方后\(p\)倍还在范围内的就有\(\sqrt{\frac{m}{p}}\)个
那么我们的算法就是\(O(n)\)的了。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace STD
{
#define ll long long
#define rr register
const int SIZE=1e7+4;
int n,ans;
ll m;
int p[SIZE];
ll read()
{
rr ll x_read=0,y_read=1;
rr char c_read=getchar();
while(c_read<'0'||c_read>'9')
{
if(c_read=='-') y_read='-';
c_read=getchar();
}
while(c_read<='9'&&c_read>='0')
{
x_read=(x_read*10)+(c_read^48);
c_read=getchar();
}
return x_read*y_read;
}
};
using namespace STD;
int main()
{
n=read(),m=read();
int en=sqrt(n);
p[1]=1;
for(rr int i=2;i<=en;i++)
p[i*i]=1;
for(rr int i=2;i<=n;i++)
if(!p[i])
{
p[i]=i;
for(rr int j=2;j<=en;j++)
{
if(j*j*i>n) break;
p[j*j*i]=i;
}
}
for(rr int i=1;i<=n;i++)
{
ll x=sqrt(m/(ll)p[i]);
if(x&1ll) ans--;
else ans++;
}
printf("%d",ans);
}
NOIP模拟13「工业题·卡常题·玄学题」的更多相关文章
- HZOI20190906模拟39 工业,卡常,玄学
题面:https://www.cnblogs.com/Juve/articles/11484209.html 工业: 推一个式子,AC 没有用组合数....推了2个多小时 我sbsbsbsbsbsbs ...
- NOIP 模拟 $13\; \text{工业题}$
题解 本题不用什么推式子,找规律(而且也找不出来) 可以将整个式子看成一个 \(n×m\) 矩阵 考虑 \(f_{i,j}\),它向右走一步给出 \(f_{i,j}×a\) 的贡献,向下走一步给出 \ ...
- NOIP模拟测试「简单的区间·简单的玄学·简单的填数·简单的序列」
简单的区间 $update$ 终于$AC$了 找到$(sum[r]+sum[l](sum表示以中间点为基准的sum)-mx)\%k==0$的点 注意这里$sum$表示是以$mid$为基准点,(即$su ...
- NOIP模拟测试39,思维禁锢专场「工业题·玄学题·卡常题」
工业题 题解 抱歉,题解没时间写了 代码 #include<bits/stdc++.h> using namespace std; #define ll long long #define ...
- Noip模拟13 2021.7.13:再刚题,就剁手&&生日祭
T1 工业题 这波行列看反就非常尴尬.....口糊出所有正解想到的唯独行列看反全盘炸列(因为和T1斗智斗勇两个半小时...) 这题就是肯定是个O(n+m)的,那就往哪里想,a,b和前面的系数分开求,前 ...
- noip模拟44[我想我以后会碰见计数题就溜走的]
noip模拟44 solutions 这一场抱零的也忒多了,我也只有45pts 据说好像是把几套题里面最难的收拾出来让我们考得 好惨烈啊,这次的考试我只有第一题骗了40pts,其他都抱零了 T1 Em ...
- NOIP 模拟 $13\; \text{卡常题}$
题解 一道环套树的最小点覆盖题目,所谓环套树就是有在 \(n\) 个点 \(n\) 条边的无向联通图中存在一个环 我们可以发现其去掉一条环上的边后就是一棵树 那么对于此题,我们把所有 \(x\) 方点 ...
- NOIP模拟测试13「矩阵游戏·跳房子·优美序列」
矩阵游戏 考试时思路一度和正解一样,考试到最后还是打了80分思路,结果80分打炸了只得了40分暴力分 题解 算出来第一列的总值,每次通过加每两列之间的差值得出下一列的总值 算第一列我们只需要让当前点* ...
- NOIP 模拟 $13\; \text{玄学题}$
题解 题如其名,是挺玄学的. 我们发现每个值是 \(-1\) 还是 \(1\) 只与它的次数是奇是偶有关,而 \(\sum_j^{j\le m}d(i×j)\) 又只与其中有多少个奇数有关 对于 \( ...
随机推荐
- Linux从头学05-系统启动过程中的几个神秘地址,你知道是什么意思吗?
作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...
- centos linux下配置固定ip,方便xshell连接
如何给centos linux设置固定ip地址,设置Linux系统的固定IP地址 首先wmware打开虚拟机 打开xshell6连接虚拟机(比较方便,这里默认设置过Linux的ip,只是不固定,每次打 ...
- 七夕特别篇|用Python绘画牛郎织女在鹊桥相见
大家好,我是辰哥~ 今天就是七夕节,首先提前祝福有伴侣的小伙伴,七夕快乐,没有伴侣的小伙伴,今天就会找到伴侣,(给看到这句话的你好运加持,哈哈哈). 作为会Python的我们必须做点好玩且有意义的东西 ...
- 【前端 · 面试 】HTTP 总结(十二)—— URL 和 URI
最近我在做前端面试题总结系列,感兴趣的朋友可以添加关注,欢迎指正.交流. 争取每个知识点能够多总结一些,至少要做到在面试时,针对每个知识点都可以侃起来,不至于哑火. 引言 不知道有多少人是和我一样分不 ...
- linux的iptables设置
添加规则 -A 在链末尾追加一条规则 -I 在链开头或某序号前插入一条规则 查看规则 -L 列出所有规则 -n 数字显示地址和端口信息 -v 详细信息 -line-numbers 显示规则序号 删除规 ...
- git 切换分支 本地代码失踪找回办法
解决方案: https://blog.csdn.net/hupoling/article/details/79017382 主要步骤: git reflog 然后找到之前commit的分支 git c ...
- Linux下库的制作(静态库与共享库)
库中实际上就是已编译好的函数代码,可以被程序直接调用. Linux下的库一般的位置在/lib或者/usr/lib中 静态库 静态库是复制拷贝到调用函数中的,函数运行的时候不再需要静态库,因为静态库是在 ...
- 理解SpingAOP
目录 什么是AOP? AOP术语 通知(Advice) 连接点(Join point) 切点(Pointcut) 连接点和切点的区别 切面(Aspect) 引入(Introduction) 织入(We ...
- rsync基本使用
概念 rsync是linux系统下的数据镜像备份工具.使用快速增量备份工具Remote Sync可以远程同步,支持本地复制,或者与其他SSH.rsync主机同步. 目前,已支持跨平台,可以在Windo ...
- js 遍历数组对象求和
这个通常是求多个商品的总价遇到的情形: [ 0: {id: 1, name: "服务费", price: "1.00"} 1: {id: 2, name: &q ...