[7.19NOIP模拟测试6]失恋三连(雾 题解
不得不说这次的题除了引起单身汪极度不适之外还是出的很有水平的……
A.
很好的dp题
模型非常简单,如果数据范围足够友好的话就是一道dp入门题
30%:
我们可以设$dp[i][j]$为到第i天一共喂食给出了j块饼干的方案数
易得转移方程:$dp[i][j+k]=\sum \limits_{k=0}^{min(m-1,n-j)}{dp[i-1][j]}$,i枚举天数,j枚举已给出数量,k枚举下一步给出数量
$\sum \limits_{i=1}^{n}{dp[i][n]}$即为答案
但是i是要枚举到d的,我们的二维数组显然开不了这么大,所以我们可以得到30分的好成绩(滑稽
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=;
const ll mod=;
int n,m;
ll dp[N][N],D;
void work()
{
if(1LL*n>=1LL*m*D||m<=)
{
puts("");
return ;
}
memset(dp,,sizeof(dp));
for(int i=;i<=min(m-,n);i++)
dp[][i]=;
for(int i=;i<=D;i++)
for(int j=;j<min(1LL*n,D*m);j++)
for(int k=;k<=min(m-,n-j);k++)
(dp[i][j+k]+=dp[i-][j])%=mod;
ll ans=;
for(int i=;i<=D;i++)
(ans+=dp[i][n])%=mod;
cout<<ans%mod<<endl;
}
int main()
{
while()
{
scanf("%d%lld%d",&n,&D,&m);
if(n==&&D==&&m==)break;
work();
}
return ;
}
(另外,冲着30分去就按着30分范围打,不要梦想把数组开到极限还能多得分……事实上博主的30分就因为数组开太大 炸了内存 没了)
100%:
d的范围十分大,但我们不难发现真正给出饼干的天数最多只有n
所以可以把上面那个状态数组的定义稍作更改:真正给出饼干天数为i,给出饼干数量为j时的方案数
另外,为了进一步优化复杂度,使用前缀和优化,我们需要对枚举变量的意义作改动,让等号左侧为$dp[i][j]$
$dp[i][j]=\sum \limits_{k=j-m+1}^{j-1}{dp[i-1][k]}$
在统计结果时,对于每个$dp[i][n]$,是从d天中选任意i天给出饼干,所以还要乘上相应组合数
即:$ans=\sum {dp[i][n]*C_d^i}$
组合数直接根据相邻两项关系递推算即可 记得不能直接除 要乘逆元
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=;
typedef long long ll;
const ll mod=;
ll dp[N][N],n,d,m,fac[N],C[N],sum[N];
ll qpow(ll a,ll b)
{
ll res=;
while(b)
{
if(b&)res=res*a%mod;
a=a*a%mod;
b>>=;
}
//if(res<0)cout<<"Jackpot!"<<endl;
return res;
}
ll inv(ll x)
{
return qpow(x,mod-);
}
void work()
{
if(n>=m*d||m<=)
{
puts("");
return ;
}
memset(dp,,sizeof(dp));
memset(sum,,sizeof(sum));
C[]=;
for(int i=;i<=min(n,d);i++)
{
C[i]=(C[i-]*(1LL*(d-i+)%mod))%mod*inv(i)%mod;
/* if(C[i]<0)while(1);
cout<<"***"<<C[i]<<endl;*/
}
for(int i=;i<m;i++)
dp[][i]=,(sum[i]=sum[i-]+dp[][i])%=mod;
for(int i=m;i<=n;i++)
sum[i]=sum[i-];
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
dp[i][j]=(sum[j-]-sum[max(0LL,j-m)]+mod)%mod;
// sum[0]=0;
for(int j=;j<=n;j++)
(sum[j]=sum[j-]+dp[i][j])%=mod;
} ll ans=;
for(int i=;i<=min(d,n);i++)
(ans+=dp[i][n]*C[i]%mod)%=mod;
cout<<ans<<endl; }
int main()
{
while()
{
scanf("%lld%lld%lld",&n,&d,&m);
if(!n&&!d&&!m)break;
work();
}
return ;
}
B.
数据很水,水到直接把这道题变成了最短路的板子……
枚举与1节点相连的点,对于每个点,把1和他们之间的边临时断开后跑最短路
用$dis[1]+len[i]$更新ans即可
正解似乎是什么二进制分组blablabla 我也不会啊
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define pa pair<int,int>
using namespace std;
const int N=,M=;
int n,m,T;
int to[M<<],dis[N],vis[N],nxt[M<<],tot,head[N],del[M<<],len[M<<];
int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*f;
}
void add(int x,int y,int z)
{
to[++tot]=y;
len[tot]=z;
nxt[tot]=head[x];
head[x]=tot;
}
void dj(int s)
{
memset(dis,0x3f,sizeof(dis));
memset(vis,,sizeof(vis));
priority_queue<pa> q;
dis[s]=;//vis[s]=1;
q.push(make_pair(,s));
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis[x])continue;
vis[x]=;
for(int i=head[x];i;i=nxt[i])
{
if(del[i])continue;
int y=to[i];
if(dis[y]>dis[x]+len[i])
{
dis[y]=dis[x]+len[i];
q.push(make_pair(-dis[y],y));
}
}
}
/*for(int i=1;i<=n;i++)
cout<<dis[i]<<' ';
puts(" ");*/
}
void ini()
{
for(int i=;i<=n;i++)head[i]=;
for(int i=;i<=m*;i++)to[i]=nxt[i]=del[i]=len[i]=;
tot=;
}
void work()
{
n=read();m=read();
ini();
for(int i=;i<=m;i++)
{
int x=read(),y=read(),z=read();
add(x,y,z);add(y,x,z);
}
int ans=0x3f3f3f3f;;
for(int i=head[];i;i=nxt[i])
{
int y=to[i];
del[i]=del[i^]=;
dj(y);
del[i]=del[i^]=;
ans=min(ans,dis[]+len[i]);
}
cout<<(ans==0x3f3f3f3f?-:ans)<<endl;
return ;
}
int main()
{
T=read();
while(T--)work();
return ;
}
(如果要使用$i\ xor\ 1$查询反边这种操作的话,链式前向星的tot初值要设成1!!!一时nc又少30!!)
C.
鬼能想到正解的神题……
首先我们考虑对这个模型进行转化。我们把2n个数字看作节点,把每张卡牌看作
是连接两个点的有向边。
于是我们的问题可以等价转化为这一问题:把图中的某些边反向使得任何一个节点
至多被一条边指向。
我们很容易想到整张图可能会被分为若干个联通块。
首先我们考虑联通块构成了树的情况。我们发现我们可以直接dp
然后我们考虑联通块构成了基环外向树的情况。我们发现只要确定环上的边的指向,
后面的外向树部分的指向就可以确定了。对于环上面的指向问题,我们发现一共只有两种
指向的可能,枚举即可。
随后我们考虑更复杂的情况,n个点,n+1条边的情况,因为我们知道每一条边肯定
会至少指向一个点,所以由抽屉原理可以一定存在一个点被指向多次,所以一定不可行。
所以,我们可以发现我们需要处理的即一个基环外向树和树的森林。
而联通块之间互不影响,分别处理即可。
树的情况需要换根进行dp。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=;
const ll mod=;
int T,n,to[N<<],nxt[N<<],head[N],tot=;
int vis[N],v[N],f[N],g[N],edge,node;
int cire,pos,poss;
vector<int> sor;
int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*f;
}
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x)
{
vis[x]=;node++;
for(int i=head[x];i;i=nxt[i])
{
edge++;
if(vis[to[i]])continue;
dfs(to[i]);
}
}
void dp1(int x,int fa)
{
v[x]=;
for(int i=head[x];i;i=nxt[i])
{
if(to[i]==fa)continue;
if(!v[to[i]])
{
dp1(to[i],x);
f[x]+=f[to[i]]+(i&);
}
else pos=x,poss=to[i],cire=i;
}
}
void dp2(int x,int fa)
{
sor.push_back(g[x]);
for(int i=head[x];i;i=nxt[i])
{
if(to[i]==fa)continue;
if(i==cire||i==(cire^))
continue;
int contr=((i&)?-:);
g[to[i]]=g[x]+contr;
dp2(to[i],x);
}
}
void ini()
{
for(int i=;i<=n*;i++)
vis[i]=v[i]=f[i]=g[i]=head[i]=;
for(int i=;i<=n*;i++)
nxt[i]=to[i]=;
tot=;edge=node=;
}
void work()
{
n=read();ini();
for(int i=;i<=n;i++)
{
int x=read(),y=read();
add(y,x);add(x,y);
}
/*for(int i=2;i<=tot;i++)
cout<<'!'<<to[i]<<' '<<nxt[i]<<' '<<endl;*/
for(int i=;i<=n;i++)
if(!vis[i])
{
node=edge=;
dfs(i);
if((edge>>)>node)
{
puts("-1 -1");
return ;
}
}
int ans1=,num=;ll ans2=;
for(int i=;i<=(n<<);i++)
{
if(v[i])continue;
sor.clear();
num=cire=pos=poss=;
dp1(i,);g[i]=f[i];
dp2(i,);
if(!cire)
{
sort(sor.begin(),sor.end());//puts("QAQ");
for(int j=;j<sor.size();j++)
{
//cout<<'!'<<sor[j]<<endl;
if(sor[j]!=sor[])break;
num++;
}
ans1+=sor[];//cout<<"***"<<ans1<<endl;
}
else
{
cire=(cire&);//puts("QwQ");
if(g[pos]+(cire^)==g[poss]+cire)num=;
else num=;
ans1+=min(g[pos]+(cire^),g[poss]+cire);//cout<<"###"<<ans1<<endl;
}
(ans2*=1LL*num%mod)%=mod;
}
/*puts("---"); for(int i=1;i<=n*2;i++)
cout<<f[i]<<' '<<g[i]<<endl;puts("---");*/
cout<<ans1<<' '<<ans2<<endl;
}
int main()
{
T=read();
while(T--)work();
return ;
}
[7.19NOIP模拟测试6]失恋三连(雾 题解的更多相关文章
- 【3.16高一(第二学期)模拟测试】 T3,T4题解
看到这个标题我想你一定会想为什么小编只发T3,T4的题解,原因有很多:1)小编也不怎么会讲:2)小编搜遍各大OJ,都没有找到可以提交的地方:3)虽然给了测试数据,小编懒得一个一个试.如果你找到了测评网 ...
- [NOIP模拟测试10]辣鸡(ljh) 题解
首先计算块内贡献,很显然是$(x_2-x_1)*(y_2-y_1)*2$. 然后考虑矩形之间的贡献,sort一遍分类讨论$n^2$暴力即可. 注意考虑边界情况是否能多两个,以及角对角的情况. 另外,排 ...
- [7.22NOIP模拟测试7]方程的解 题解(扩展欧几里得)
Orz 送分比较慷慨的一道题,疯狂特判能拿不少分. 对于$a>0,b>0$的情况: 用exgcd求出方程通解,然后通过操作得到最小正整数解和最大正整数解 他们以及他们之间的解满足等差数列性 ...
- csp-s模拟测试52平均数,序列题解
题面:https://www.cnblogs.com/Juve/articles/11602244.html 平均数: 第k个平均数不好求,我们考虑二分,转化成平均数小于x的有几个 虑把序列中的每个数 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...
- Android单元测试与模拟测试详解
测试与基本规范 为什么需要测试? 为了稳定性,能够明确的了解是否正确的完成开发. 更加易于维护,能够在修改代码后保证功能不被破坏. 集成一些工具,规范开发规范,使得代码更加稳定( 如通过 phabri ...
- [开源]微信在线信息模拟测试工具(基于Senparc.Weixin.MP开发)
目前为止似乎还没有看到过Web版的普通消息测试工具(除了官方针对高级接口的),现有的一些桌面版的几个测试工具也都是使用XML直接请求,非常不友好,我们来尝试做一个“面向对象”操作的测试工具. 测试工具 ...
- 安装nginx python uwsgi环境 以及模拟测试
uwsgi帮助文档: http://uwsgi-docs-cn.readthedocs.io/zh_CN/latest/WSGIquickstart.html http://uwsgi-docs.re ...
- 利用Python中的mock库对Python代码进行模拟测试
这篇文章主要介绍了利用Python中的mock库对Python代码进行模拟测试,mock库自从Python3.3依赖成为了Python的内置库,本文也等于介绍了该库的用法,需要的朋友可以参考下 ...
随机推荐
- linux查看java jdk jre安装路径和设置环境变量
一. 查看java jdk安装路径和设置环境变量 windows: set java_home:查看JDK安装路径 java -version:查看JDK版本 linux: whereis java ...
- react教程 — 开发 总结
本文章是在熟练使用 VUE 的基础上,对比VUE 功能进行的一个技术总结. 1.react项目快速搭建 https://blog.csdn.net/mapbar_front/article/deta ...
- Name your feature branches by convention
https://docs.microsoft.com/en-us/azure/devops/repos/git/git-branching-guidance?view=azure-devops Nam ...
- java中 抽象类和接口的区别
一. 什么是抽象类及什么是抽象方法 抽象方法是一种特殊的方法:他只有声明,而没有具体实现,抽象方法的声明格式为: abstract void funName(); 抽象方法必须用 abstract 修 ...
- JS对象中属性的增删改查
对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性 对象的分类: 1.内建对象 -在ES标准中定义的对象,在任何的ES的实现中都可以 ...
- shell getopts命令
由于shell命令行的灵活性,自己编写代码判断时,复杂度会比较高.使用内部命令 getopts 可以很方便地处理命令行参数.一般格式为: getopts optstring name [args] ...
- Linux下设置Core文件生成路径及文件名
修改core dump文件路径: 方法1:临时修改: 修改/proc/sys/kernel/core_pattern文件/proc目录本身动态加载每次系统重启都会重新加载因此种方法只能作临时修改/p ...
- windows下虚拟环境的安装与创建
使用虚拟环境的好处: 可以方便的解决不同项目对类库的依赖问题. 可以在系统中Python解释器中避免包的混乱和版本的冲突. 为每个程序单独创建虚拟环境,可以保证程序只能访问虚拟环境中的包,保持全局解释 ...
- CVE-2010-4258漏洞分析
Nelson Elhage最近发现了一个内核设计上的漏洞, 通过利用这个漏洞可以将一些以前只能dos的漏洞变成可以权限提升的漏洞. 当fork一个进程在的时候, copy_process执行如下操作: ...
- sql语句(删除重复数据只保留一条)
用SQL语句,删除掉重复项只保留一条 在几千条记录里,存在着些相同的记录,如何能用SQL语句,删除掉重复的呢 1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断 select ...