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. XCTF csaw2013reversing2

    题目描述:听说运行就能拿到Flag,不过菜鸡运行的结果不知道为什么是乱码 一.先运行看看. 果然乱码. 二.查壳 三.是pe文件,可以拖入od和ida进行动态和静态分析. 1.对主函数进行反编译一下. ...

  2. Mybatis代码自动生成(含测试)

    一.建立数据库 create database shixun; use shixun; create table user( id int primary key auto_increment , u ...

  3. Vue使用PrintJs自定义打印表格模板

    这俩天客户提了个需求,需要打印俩个自定义的表格模板,一开始想到的是打印Json表格,但是发现表格样式不符合要求,后来想着打印html,自己生成html模板然后打印,基本可以满足客户的需求,废话不多说, ...

  4. ESP32构建系统 (传统 GNU Make)

    概述: 一个 ESP-IDF 项目可以看作是多个不同组件的集合,ESP-IDF 可以显式地指定和配置每个组件.在构建项目的时候,构建系统会前往 ESP-IDF 目录.项目目录和用户自定义目录(可选)中 ...

  5. 「AGC010F」 Tree Game

    「AGC010F」 Tree Game 传送门 切了一个 AGC 的题,很有精神. 于是决定纪念一下. 首先如果任意一个人在点 \(u\),他肯定不会向点权大于等于 \(a_u\) 的点走的,因为此时 ...

  6. 日常学习-001-Get和Post的区别

    首先说明参考链接:https://mp.weixin.qq.com/s/W68JzNIoUpm9hyXinOzkMw 以下为个人观后总结. 初级理解: GET和POST的区别 1.get传送的参数长度 ...

  7. SQLITE数据库不支持远程访问

    SQLITE数据库不支持远程访问 import sqlite3 conn=sqlite3.connect("dailiaq.db") cur=conn.cursor() def c ...

  8. python 操作word

    pip install python.docx from docx import DocumentDoc = Document() 解释:from 从 docx这个文件中,导入一个叫Document的 ...

  9. Python基础之函数的闭包与装饰器的介绍

    1.闭包的概念: 如果在一个函数中,定义了另外一个函数,并且那个函数使用了外面函数的变量,并且外面那个函数返回了里面这个函数的引用,那么称为里面的这个函数为闭包. 2.话不多说,以demo示例: de ...

  10. 一定要收藏的5个优秀的SpringCloud开源项目

    上一期为大家推荐了几个前端模板,没看过的点下面 一定要收藏的5个后台管理系统的前端框架 今天再为大家推荐几个优秀的SpringCloud开源脚手架项目,开箱即用,不管是学习还是开发新项目,都非常不错. ...