T1

首先,这个插球,就是森林中连点,考虑dp,我们设 \(dp_{i,j}\) 表示有i个点的森林,有j个点在第一颗树中的概率,转移时考虑第i个点是否在第一颗子树里,转移方程:

\[dp_{i,j}=dp_{i-1,j-1}\times (j-1)\times inv_{i}+dp_{i-1,j}\times (i-j)\times inv_{i}
\]

设 \(f_{i,j}\) 表示有i个的树,深度不超过j的概率,\(g_{i,j}\) 表示有i个点的森林,深度不超过j的概率,转移方程为:

\[f_{i,j}=g_{i-1,j-1}
\]
\[g_{i,j}=\sum_{k=1}^{i} f_{k,j}\times g_{i-k,j}\times dp_{i,k}
\]

比较恶心的是初始化,按照定义来初始化就好,就是容易漏情况,具体看code。

注意取模QAQ

Code
#include<cstdio>
#define N 220
#define re register
#define int long long
namespace OMA
{
int n,p,inv[N],sum;
int dp[N][N],f[N][N],g[N][N];
inline int quickpow(int a,int b)
{
int ans = 1;
while(b)
{
if(b&1)
{ ans = ans*a%p; }
a = a*a%p;
b >>= 1;
}
return ans;
}
signed main()
{
scanf("%lld%lld",&n,&p);
dp[1][1] = dp[1][0] = 1;
inv[0] = 1,inv[n] = quickpow(n,p-2);
for(re int i=n-1; i>=1; i--)
{ inv[i] = quickpow(i,p-2); }
for(re int i=2; i<=n; i++)
{
for(re int j=1; j<=i; j++)
{ dp[i][j] = ((dp[i-1][j-1]*(j-1)%p*inv[i]%p+dp[i-1][j]*(i-j)%p*inv[i]%p)%p+p)%p; }
}
for(re int i=0; i<=n; i++)
{ f[0][i] = g[0][i] = 1; }
for(re int i=1; i<=n; i++)
{
for(re int j=i-1; j<=n; j++)
{ f[i][j] = g[i][j] = 1; }
}
for(re int i=2; i<=n; i++)
{
for(re int j=0; j<=i-2; j++)
{
if(j)
{ f[i][j] = g[i-1][j-1]; }
for(re int k=1; k<=i; k++)
{ (g[i][j] += f[k][j]*g[i-k][j]%p*dp[i][k]%p) %= p; }
}
}
for(re int i=1; i<=n; i++)
{ (sum += ((f[n][i]-f[n][i-1])*i%p+p)%p) %= p; }
printf("%lld\n",sum);
return 0;
}
}
signed main()
{ return OMA::main(); }

T2

考试的时候想骗 \(c=0\) 的点,结果挂了,

90 1 19

16 79 0

傻逼数据,1不连边

记搜有72pts..

TLE 72pts
#include<bitset>
#include<cstdio>
#define re register
const int N = 111;
const int M = 8500;
namespace OMA
{
int n,m,d,ans;
struct graph
{
int next;
int to;
int w;
}edge[M<<1];
int staa[1<<21];
std::bitset<1<<20>vis[N][N];
int cnt=1,head[N];
inline int read()
{
int s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*w;
}
inline void add(int u,int v,int w)
{
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt;
}
inline void dfs(int u,int sta,int dnt)
{
if(vis[u][dnt][sta])
{ return ; }
if(dnt==d)
{ if(!staa[sta]){ ans++,staa[sta] = 1; } return ; }
vis[u][dnt][sta] = 1;
for(re int i=head[u]; i; i=edge[i].next)
{
int v = edge[i].to,w = edge[i].w;
int stat = sta|(w<<dnt);
dfs(v,stat,dnt+1);
}
}
signed main()
{
n = read(),m = read(),d = read();
for(re int i=1,u,v,w; i<=m; i++)
{
u = read(),v = read(),w = read();
add(u,v,w),add(v,u,w);
}
dfs(1,0,0);
printf("%d\n",ans);
return 0;
}
}
signed main()
{ return OMA::main(); }

正解:

显然是状压,设 \(dp_{i,j,mask}\) 表示从i出发,到j结束,是否存在一条状态为mask的路径,最后枚举转移答案,但直接转移会T掉题解里说的,考虑如何优化

meet in the middle+bitset

具体实现可见代码。

时间复杂度 \(O(2^{\frac{d}{2}}\times n\times (n+m)+2^{d}\times n)\)

也是题解里说的

Code
#include<bitset>
#include<cstdio>
#include<cstring>
#define re register
const int N = 221;
const int M = 8500;
const int MASK = 1<<10+1;
namespace OMA
{
int n,m,d[3],ans;
std::bitset<N>dp[MASK][2],link[N][2];
inline int read()
{
int s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*w;
}
signed main()
{
n = read(),m = read(),d[0] = read();
for(re int i=1,u,v,w; i<=m; i++)
{
u = read(),v = read(),w = read();
link[u][w][v] = link[v][w][u] = 1;
}
d[2] = d[0]-(d[1] = d[0]/2);
int mask[2] = {1<<d[1],1<<d[2]};
for(re int u=n; u; u--)
{
for(re int i=0; i<MASK; i++)
{ dp[i][0].reset(); }
dp[1][0][u] = 1;
for(re int i=0; i<=mask[1]-1; i++)
{
for(re int v=1; v<=n; v++)
{
if(dp[i][0][v])
{ dp[i<<1][0] |= link[v][0],dp[i<<1|1][0] |= link[v][1]; }
}
}
for(re int i=0; i<=mask[1]-1; i++)
{ dp[i][1][u] = dp[mask[1]|i][0].any(); }
}
for(re int i=0; i<=mask[1]-1; i++)
{
for(re int j=0; j<=mask[0]-1; j++)
{
if((dp[mask[0]|j][0]&dp[i][1]).any())
{ ans++; }
}
}
printf("%d\n",ans);
return 0;
}
}
signed main()
{ return OMA::main(); }

T3

暴力30pts+ \(q=0\) 1pts+单调14pts

单调包括递增和递减,注意一下。

45pts


#include<cmath>
#include<cstdio>
#define MAX 100100
#define re register
#define int long long
namespace OMA
{
int n,q;
int x[MAX],len[MAX];
inline int read()
{
int s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*w;
}
inline int abs(int a)
{ return a>=0?a:-a; }
inline void task1()
{
int l,r;
long long cast;
for(re int i=1; i<=q; i++)
{
cast = l = 0,r = len[i];
for(re int j=1; j<=n; j++)
{
//printf("l=%d r=%d to=%d ",l,r,x[j]);
if((r>x[j]&&l<x[j])||(r==x[j])||(l==x[j]))
{ continue ; }
else if(abs(r-x[j])<abs(l-x[j]))
{ cast += abs(r-x[j]),r = x[j],l = r-len[i]; }
else
{ cast += abs(l-x[j]),l = x[j],r = l+len[i]; }
//printf("haven casted:%d\n",cast);
}
printf("%lld\n",cast);
}
}
inline void task2()
{
int cnt[2] = {0,0}; // up down
for(re int i=2; i<=n; i++)
{
if(x[i]>x[i-1])
{ cnt[0]++; }
else if(x[i]<x[i-1])
{ cnt[1]++; }
}
if(cnt[0]==n-1)
{
if(x[1]>=0)
{
for(re int i=1; i<=q; i++)
{ printf("%lld\n",(len[i]<x[n])?(x[n]-len[i]):0); }
}
else
{
for(re int i=1; i<=q; i++)
{ printf("%lld\n",abs(x[1])+abs(x[n]-x[1]-len[i])); }
}
}
if(cnt[1]==n-1)
{
for(re int i=1; i<=q; i++)
{
int cast = 0;
if(x[1]>len[i])
{ cast = x[1]-len[i]; }
if(x[n]<cast)
{ cast += cast-x[n]; }
printf("%lld\n",cast);
}
}
}
inline void task3()
{ ; }
inline void task4()
{ ; }
signed main()
{
//freopen("node.in","r",stdin);
//freopen("my.out","w",stdout);
n = read(),q = read();
for(re int i=1; i<=n; i++)
{ x[i] = read(); }
for(re int i=1; i<=q; i++)
{ len[i] = read(); }
if(q==0)
{ return 0; }
if(n<=1e3)
{ task1(); }
else
{
task2();
//task3();
//task4();
}
return 0;
}
}
signed main()
{ return OMA::main(); }

正解不会...,所以,



所以为什么给的std只能拿30pts啊,单调还判错了

updated on 7.21

好吧,std换成对的了 是指针好吧,是迭代器,可恶

没改出来,贴下std吧..

std
#include<bits/stdc++.h>
using namespace std; typedef long long ll;
const int maxn=1e5+10;
int n,m;
ll tot,ans[maxn];
vector<int> x;
vector<pair<int,int> > a;
map<int,int> mp; inline ll calc(ll k){
if(!mp.empty()&&mp.begin()->second<0)
return tot-(mp.size()-1)*k;
else
return tot-mp.size()*k;
}
inline void solve(){
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
int t=0;
for(int i=0;i<x.size();++i){
tot+=abs(x[i]);
mp[i]=x[i];
q.push(make_pair(abs(x[i]),i));
}
while(!q.empty()){
int id=q.top().second,tmp=q.top().first;q.pop();
map<int,int>::iterator p=mp.lower_bound(id);
if(p==mp.end()||p->first!=id||abs(p->second)!=tmp)
continue;
while(t<a.size()&&abs(p->second)>a[t].first)
ans[a[t].second]=calc(a[t].first),++t;
if(p!=mp.begin())
if(p!=prev(mp.end())){
tmp=p->second,tot-=abs(p->second);
tmp+=prev(p)->second,tot-=abs(prev(p)->second);
tmp+=next(p)->second,tot-=abs(next(p)->second);
mp.erase(prev(p));
mp.erase(next(p));
p->second=tmp,tot+=abs(tmp);
q.push(make_pair(abs(tmp),id));
}
else{
tot-=abs(p->second);
mp.erase(p);
}
else if(p->second>0)
if(p!=prev(mp.end())){
tmp=p->second,tot-=abs(p->second);
tmp+=next(p)->second,tot-=abs(next(p)->second);
mp.erase(next(p));
if(tmp){
p->second=tmp,tot+=abs(tmp);
q.push(make_pair(abs(tmp),id));
}
else
mp.erase(p);
}
else{
tot-=abs(p->second);
mp.erase(p);
}
}
while(t<a.size())
ans[a[t].second]=calc(a[t].first),++t;
} int main(){ scanf("%d%d",&n,&m);
for(int i=0,p,last=0;i<n;++i){
scanf("%d",&p);
if(p==last)
continue;
if(!x.empty()&&(x.back()<0&&p<last||x.back()>0&&p>last))
x.back()+=p-last;
else
x.push_back(p-last);
last=p;
}
for(int i=0,l;i<m;++i){
scanf("%d",&l);
a.push_back(make_pair(l,i));
}
sort(a.begin(),a.end());
solve();
for(int i=0;i<m;++i)
printf("%lld\n",ans[i]);
return 0;
}

所以 \(\frac{1}{4}\) 是有多喜欢STL啊

noip20的更多相关文章

  1. 20210719 noip20

    考场 后两题是原题,教练说不用写了(ycx 不讲武德) T1 先手模了 \(n\le5\) 的情况,尝试找规律失败.那就只能 DP 了,最终没搞出来. 记忆化搜索打了 \(n\le20\) 的表,交了 ...

随机推荐

  1. buu 不一样的flag

    一.查壳 二.拖入ida,分析 从这里和51到53行的代码,基本判断这是一个迷宫题,并且是5行5列的一个迷宫.我当时感觉到一个奇怪的地方是 第一个,我自己想明白是因为可能是int型,数字占了4个字节, ...

  2. SEO优化:如何挖掘关键词谷歌篇

    最近SEO禅在做安卓项目比较忙,大部分入门理论的文章也写了差不多了,有的也写了一个系列,但是感觉还是不够完善,有很多边边角角的地方感觉也没说清楚,所以还是有必要写一些零散文章去补充说明下,就比如关于S ...

  3. stream之map的用法

    一.Stream管道流map的基础用法 最简单的需求:将集合中的每一个字符串,全部转换成大写! List<String> alpha = Arrays.asList("Monke ...

  4. 基于JSP的学生考勤管理系统(MySQL版)

    介绍:基于JSP的学生考勤管理系统(MySQL版)1.包含源程序,数据库脚本.代码和数据库脚本都有详细注释.2.课题设计仅供参考学习使用,可以在此基础上进行扩展完善.开发环境:Eclipse ,MyS ...

  5. ZooKeeper 分布式锁 Curator 源码 04:分布式信号量和互斥锁

    前言 分布式信号量,之前在 Redisson 中也介绍过,Redisson 的信号量是将计数维护在 Redis 中的,那现在来看一下 Curator 是如何基于 ZooKeeper 实现信号量的. 使 ...

  6. CentOS更换网易yum源

    最新内容和地址参见http://mirrors.163.com/.help/centos.html 1 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yu ...

  7. Python+Requests+Xpath实现动态参数获取实战

    1.古诗文网直接登录时,用浏览器F12抓取登录接口的入参,我们可以看到框起来的key对应的value是动态参数生成的,需获取到: 2.登录接口入参的值一般是登录接口返回的原数据值,若刷新后接口与对应源 ...

  8. python基础之文件的读取

    #文件名 txt文件的读取#文件的读取 open("文件","读写方法") with open("文件","读写方法") ...

  9. Java 给Word添加印章

    一.概述 本文以Java程序代码展示如何给Word文档添加印章,这里添加的印章为.png格式的图片,添加印章即在Word中的指定位置添加印章图片. 基本思路:加载word文档,获取段落,在段落中插入图 ...

  10. 深入刨析tomcat 之---第15篇 对应20章, myAdmin案例代码

    writedby 张艳涛 有没有和我一样做到第20章的?今天基本结束了本书的阅读.最后一个案例没有demo,那我写了一回,如果有需要的可以在本地试试 路径 D:\wksp_study\designbo ...