四连测Day4
四连爆炸
卡我常数
好像被AluminumGod拉到了创客...哇我这个天天爆炸的水平可能会被其他三位dalao吊起来打
orz Edmond-Karp_XiongGod
orz Deidara_WangGod
orz Small_ChickenGod
T1 树上有一些关键点,求包含i个关键点的联通块数,0<=i<=m
n,m<=1000
树形dp,强行证明复杂度
#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) x=x*+ch-'',ch=getchar();
return x*f;
}
const int maxn = ,mod = ;
vector<int> G[maxn];
int n,m;int a[maxn];
int state;
LL f[maxn][maxn],size[maxn],ans[maxn];
inline void dp(int x,int fa)
{
size[x] = ;
if(a[x] == )f[x][] = ;
else f[x][] = ;
for(auto to : G[x])
{
if(to == fa)continue;
dp(to,x);size[x] += size[to];
for(int i=size[x];i>=;i--)
{
for(int j=;j<=i && j<=size[to];j++)
(f[x][i] += 1ll * f[to][j] * f[x][i - j]) %= mod;
}
}
for(int i=;i<=size[x];i++)(ans[i] += f[x][i]) %= mod;
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n = read(),m = read();
for(int i=;i<=m;i++)a[read()] = ;
for(int i=;i<n;i++)
{
int u = read(),v = read();
G[u].push_back(v);G[v].push_back(u);
}
dp(,);
for(int i=;i<=m;i++)printf("%lld ",ans[i]);
}
(虽然不是严格n^2但也卡不到n^3 比标算慢一点)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define MAXN 131072
#define MOD 998244353
using namespace std;
inline int read()
{
int x=,t=,c;
while(!isdigit(c=getchar()))if(c=='-')t=-;
while(isdigit(c))x=x*+c-'',c=getchar();
return x*t;
}
int first[],nxt[],targ[],cnte=;
bool special[];
int ans[];
int dp[][],cntd[];
int poly[];
void AddEdge(int u,int v)
{
targ[cnte]=v;nxt[cnte]=first[u];first[u]=cnte++;swap(u,v);
targ[cnte]=v;nxt[cnte]=first[u];first[u]=cnte++;
}
void DP(int x,int Fa)
{
if(special[x])
{
dp[x][]=;cntd[x]=;
}
else
{
dp[x][]=;cntd[x]=;
}
for(int i=first[x];i;i=nxt[i])
{
if(targ[i]==Fa)continue;
int y=targ[i];
DP(y,x);
for(int i=;i<cntd[x]+cntd[y]-;i++)poly[i]=;
for(int i=;i<cntd[x];i++)
for(int j=;j<cntd[y];j++)
(poly[i+j]+=(long long)dp[x][i]*dp[y][j]%MOD)%=MOD;
cntd[x]+=cntd[y]-;
for(int i=;i<cntd[x];i++)dp[x][i]=poly[i];
}
for(int i=;i<cntd[x];i++)(ans[i]+=dp[x][i])%=MOD;
dp[x][]++;dp[x][]%=MOD;
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
int n=read(),m=read();
for(int i=;i<m;i++)special[read()]=;
for(int i=;i<n;i++)AddEdge(read(),read());
DP(,);
for(int i=;i<=m;i++)printf("%d%c",ans[i],i==m?'\n':' ');
}
(集训队dalao的标算)
T2
每个机器人对每个零件有一个需求度,现在你有$n$个机器人$m$个零件,第$i$个机器人需要$ki$个零件,求所有机器人需求度和的最大值
费用流
S->机器人 caps = ki,cost = 0
机器人->零件 caps = 1,cost = 需求度
零件->T caps = 1,cost = 0
然后跑最大费用最大流
#include<bits/stdc++.h>
using namespace std;
const int maxn = * * ;
long long ans;//此处ans保存费用
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) x=x*+ch-'',ch=getchar();
return x*f;
}
int n,m,s,t;
int first[maxn],to[maxn],nx[maxn],caps[maxn],cost[maxn],cnt=-;
int vis[maxn],dis[maxn];
deque<int> dq;
inline void add(int u,int v,int w,int c)
{
to[++cnt]=v;
nx[cnt]=first[u];
first[u]=cnt;
caps[cnt]=w;
cost[cnt]=c;
}
inline void ins(int u,int v,int w,int c){add(u,v,w,c);add(v,u,,-c);}
inline int afps(int s,int t)//反向spfa
{
memset(vis,,sizeof(vis));
memset(dis,,sizeof(dis));
dis[t]=;vis[t]=;
dq.clear();
dq.push_back(t);
while(!dq.empty())
{
int now=dq.front();dq.pop_front();
for(int i=first[now];i>-;i=nx[i])
if(caps[i^] && dis[to[i]]>dis[now]-cost[i])
{
dis[to[i]]=dis[now]-cost[i];
if(!vis[to[i]])
{
vis[to[i]]=;
if(!dq.empty() && dis[to[i]]<dis[dq.front()])dq.push_front(to[i]);
else dq.push_back(to[i]);
}
}
vis[now]=;
}
return dis[s]<;
}
inline int dfs(int u,int flow)
{
if(u==t){vis[t]=;return flow;}
int used=,tmp;vis[u]=;
for(int i=first[u];i>-;i=nx[i])
if(!vis[to[i]] && caps[i] && dis[u]-cost[i]==dis[to[i]])
{
tmp=dfs(to[i],min(caps[i],flow-used));
if(tmp)ans+=1ll*tmp*cost[i],caps[i]-=tmp,caps[i^]+=tmp,used+=tmp;
if(used==flow)break;
}
return used;
}
inline int zkw()
{
long long maxflow=;
while(afps(s,t))
{
vis[t]=;
while(vis[t])
{
memset(vis,,sizeof(vis));
maxflow+=(long long)dfs(s,);
}
}
return maxflow;
}
int main()
{
freopen("robot.in","r",stdin);
freopen("robot.out","w",stdout);
memset(nx,-,sizeof nx);memset(first,-,sizeof first);
n=read(),m=read();s = ;t = n + m + ;
for(int i=;i<=n;i++)
{
int a = read();
ins(s,i,a,);
}
for(int i=;i<=m;i++)ins(i + n,t,,);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
int a = read();
ins(i,j + n,,-a);
}
}
zkw();
printf("%d",-ans);
}
需要注意的是这道题图很稠密,EK被卡成了暴力分
T3
有一维空间内$n$个点,编号从$1$到$n$,编号为$i$的点坐标为$x_i$。
现在,请选出编号连续的一些点,使得被选出的所有点到某一点的距离和的最小值不超过一正
整数$m$,问最多选出多少点?
$O(nlog^2n)$的做法:(卡常的出题人嘤嘤嘤qwq)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
int x = ,f = ;char ch = getchar();
while(!isdigit(ch)){if(ch == '-') f = -;ch = getchar();}
while(isdigit(ch)) x = x * + ch - '',ch = getchar();
return x * f;
}
const int maxpos = ;
int n,m;
int res;
int va[maxpos * + ];
int size[maxpos * + ];
int a[];
#define ls (x << 1)
#define rs ((x << 1) | 1)
inline void Insert(int x,int l,int r,int val,int f)
{
if(l == r){size[x] += f;va[x] += (l * f);return;}
int mid = (l + r) >> ;
if(val <= mid) Insert(ls,l,mid,val,f);
else Insert(rs,mid + ,r,val,f);
va[x] = va[ls] + va[rs];
size[x] = size[ls] + size[rs];
}
inline int kth(int x,int l,int r,int val)
{
if(l == r)return l;
int mid = (l + r) >> ;
if(val <= size[ls]) return kth(ls,l,mid,val);
else return kth(rs,mid + ,r,val - size[ls]);
}
inline int query(int x,int l,int r,int L,int R)
{
if(L<= l && R >= r){res += size[x];return va[x];}
int mid = (l + r) >> ;
int ret = ;
if(L <= mid)ret += query(ls,l,mid,L,R);
if(R > mid)ret += query(rs,mid + ,r,L,R);
return ret;
}
inline int check(int mid)
{
memset(va,,sizeof(va));memset(size,,sizeof(size));
for(int i = ;i <= mid;i++)Insert(,,maxpos,a[i],);
int pos = kth(,,maxpos,(mid + ) >> );
res = ;
int ans = query(,,maxpos,,pos);
if( ( ( res * pos ) - ans ) + ( va[] - ans) - ( (mid - res ) * pos) <= m) return ;//!!!
for(int i = mid + ;i<=n;i++)
{
Insert(,,maxpos,a[i - mid], - );
Insert(,,maxpos,a[i],);
pos = kth(,,maxpos,(mid + ) >> );
res = ;
ans = query(,,maxpos,,pos);
if( ( ( res * pos ) - ans ) + ( va[] - ans) - ( (mid - res ) * pos) <= m) return ;//!!!
}
return ;
}
int main()
{
freopen("choose.in","r",stdin);
freopen("choose.out","w",stdout);
n = read(),m = read();
for(int i = ;i <= n;i++)a[i] = read();
int l = ,r = n,ans;
while(l <= r)
{
int mid = (l + r) >> ;
if(check(mid)) {l = mid + ;ans = mid;}
else r = mid - ;
}
printf("%d\n",ans);
}
$O(nlogn)$的做法:(放份好看的)
。。。还是来写一下标算的做法吧
可以知道到“某一点距离和的最小值”一定是这几个点的中位数
维护一个滑动窗口,每次用平衡树查询窗口内的答案,看合不合法,处理出以每个点开头/结尾的滑窗的最长长度即可
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<vector>
#include<set>
#define MAXN 100100
#define MAXX 1001000
#define ll long long
#define inf 2139062143
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
int n,m,l,ans,g[MAXN],val[MAXX<<],maxn;
ll sum[MAXX<<];
void mdf(int k,int l,int r,int x,int p)
{
if(l==r) {sum[k]+=p*x,val[k]+=p;return ;}
int mid=(l+r)>>;
if(x<=mid) mdf(k<<,l,mid,x,p);
else mdf(k<<|,mid+,r,x,p);
sum[k]=sum[k<<]+sum[k<<|],val[k]=val[k<<]+val[k<<|];
}
ll Ask(int k,int l,int r,int x)
{
if(l==r) return val[k]*maxn+l;
int mid=(l+r)>>;
if(val[k<<]>=x) return Ask(k<<,l,mid,x);
else return Ask(k<<|,mid+,r,x-val[k<<]);
}
ll query(int k,int l,int r,int a,int b)
{
if(a>b) return ;
if(l==a&&r==b) return sum[k];
int mid=(l+r)>>;
if(b<=mid) return query(k<<,l,mid,a,b);
else if(a>mid) return query(k<<|,mid+,r,a,b);
else return query(k<<,l,mid,a,mid)+query(k<<|,mid+,r,mid+,b);
}
int lft(int k,int l,int r,int a,int b)
{
if(a>b) return ;
if(l==a&&r==b) return val[k];
int mid=(l+r)>>;
if(b<=mid) return lft(k<<,l,mid,a,b);
else if(a>mid) return lft(k<<|,mid+,r,a,b);
else return lft(k<<,l,mid,a,mid)+lft(k<<|,mid+,r,mid+,b);
}
ll calc(int x)
{
if(x==l) return ;
if(x-l==) return abs(g[x]-g[l]);
ll t=(x-l+)/+,k=Ask(,,maxn,t),lv=lft(,,maxn,,k%maxn-),q= k/maxn+*lv-x+l-;k%=maxn;
return query(,,maxn,k+,maxn)-query(,,maxn,,k-)+q*k;
}
int main()
{
freopen("choose.in","r",stdin);
freopen("choose.out","w",stdout);
n=read(),m=read();
for(int i=;i<=n;i++) g[i]=read(),maxn=max(maxn,g[i]);
for(int i=l=;i<=n;i++)
{
mdf(,,maxn,g[i],);
while(calc(i)>m) {mdf(,,maxn,g[l],-);l++;}
ans=max(ans,i-l+);
}
printf("%d",ans);
}
出题人为了卡我的常,甚至使用了前两题开O2这题临时不开的技巧...
嘤
四连测Day4的更多相关文章
- 【2018.8.10】四连测day4 题解
T1:给出一棵 $n$ 个节点的无根树,其中 $m$ 个节点是特殊节点,求对于任意 $i ∈ [0, m]$,包含 $i$ 个特殊节点的联通块个数$\mod 998244353$. $1<=n, ...
- 四连测总结(XYX)
目录 成绩 总结 事后... 成绩 telephonewire monkey 总分 0 56 56 cowjog guard path temperature 总分 0 40 0 68 108 cba ...
- 正睿 2018 提高组十连测 Day4 T3 碳
记'1'为+1,'0'为-1; 可以发现 pre[i],suf[i]分别为前/后缀和 a[i]=max(pre[l.....i]); b[i]=max(suf[i+1....r]); ans=max( ...
- 四连测Day3
题目链接:https://pan.baidu.com/s/1_vsHfMI_qO-9IDxmFLkHfg 密码: uza8 T1: 小奥的一笔画,判连通性,查奇偶点即可 #include<ios ...
- 四连测Day2
题目:链接: https://pan.baidu.com/s/1ef_9hGBhczW0B4dz5IUKmw 密码: qgjy T1: hash后直接二分查询即可 #include<iostre ...
- 四连测Day1
题目:链接: https://pan.baidu.com/s/163ycV64ioy7uML7AvRDTGw 密码: p86i T1: 倍增求LCA,minn数组记录最小值 #include<i ...
- (四连测)滑雪场的高度差题解---二分 + 搜索---DD(XYX)的博客
滑雪场的高度差 时间限制: 1 Sec 内存限制: 128 MB 题目描述 滑雪场可以看成M x N的网格状山地(1 <= M,N <= 500),每个网格是一个近似的平面,具有水平高度 ...
- STM32—TIMx实现编码器四倍频
文章目录 一.储备知识 二.TIMx的编码器模式介绍 1.计数边沿设置 2.选择极性和使能 3.使能 4.计数方向 三.代码部分 一.储备知识 通过STM32的定时器编码器接口模式对编码器进行四倍频, ...
- Android支付接入(七):Google In-app-Billing
前段时间有事请耽搁了,今天跟大家一起看下Google的in-app Billing V3支付. 如果没有Google Play此处附上安装Google Play的一键安装器的链接(需要Root权 ...
随机推荐
- Qt on Android:将Qt调试信息输出到logcat中
版权全部 foruok .如需转载敬请注明出处(http://blog.csdn.net/foruok). 假设你在目标 Android 设备上执行了 Qt on Android 应用,你可能希望看到 ...
- Chapter 4 马尔科夫链
4.1 引言 现在要研究的是这样一种过程: 表示在时刻的值(或者状态),想对一串连续时刻的值,比如:,, ... 建立一个概率模型. 最简单的模型就是:假设都是独立的随机变量,但是通常这种假设都是没什 ...
- Mysql 索引增加与删除
[1]索引 索引,通俗理解,即目录. 之前说过,计算机是对现实世界的模拟.目录应用在数据库领域,即所谓的索引. 目录的作用显而易见,所以建立索引可以大大提高检索的速度. 但是,会降低更新表的速度,如对 ...
- git连接到github(SSH无密码登陆)
[0]README 0.1)本文旨在尝试在linux环境下免密码连接到github,并进行push + pull projects in github by git commands. 0.1) 对s ...
- MySQL中使用INNER JOIN来实现Intersect并集操作
MySQL中使用INNER JOIN来实现Intersect并集操作 一.业务背景 我们有张表设计例如以下: CREATE TABLE `user_defined_value` ( `RESOURCE ...
- PHP 获取网络接口文件流
获取网络接口里面的文件流 php开发调用各种接口在所难免,有时须要传递非常多參数. 在传递參数过程中 '&' 有时会被 解析成 '&'导致请求失败 经过查找资料和比較,发现php提供了 ...
- PHP错误调试
一:错误类型举例 1.语法错误:一般是语句最后缺少分号.缺少单引号或双引号.for循环或函数缺少花括号.缺少变量标示符$ 2.定义错误:一般是调用不存在的变量.调用不存在的函数或者类 3.逻辑错误:代 ...
- 【BZOJ2626】JZPFAR kd-tree+堆
[BZOJ2626]JZPFAR Description 平面上有n个点.现在有m次询问,每次给定一个点(px, py)和一个整数k,输出n个点中离(px, py)的距离第k大的点的标号.如果有两个( ...
- EasyNVR如何实现跨域鉴权
EasyNVR提供简单的登录鉴权,客户端通过用户名密码登录成功后,服务端返回认证token的cookie, 后续的接口访问, 服务端从cookie读取token进行校验. 但是, 在与客户系统集成时, ...
- Python 进程、线程、协程、锁机制,你知多少?
1.python的多线程到底有没有用? 2. 为什么在python里推荐使用多进程而不是多线程 3.进程.线程.协程.各种锁 4.Python多进程编程