2017 清北济南考前刷题Day 4 morning

考场思路:
倒着算就是
可以对一个数-1
可以合并两个数
可以证明只有0和0才能执行合并操作
然后模拟
#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; #define N 1000001 void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} int a[N]; int main()
{
//freopen("multiset.in","r",stdin);
// freopen("multiset.out","w",stdout);
int n;
read(n);
int sum0=,cnt=,x;
for(int i=;i<=n;i++)
{
read(x);
if(!x) sum0++;
else a[++cnt]=x;
}
sort(a+,a+cnt+);
long long ans=,gather=;
for(int i=;i<=cnt;i++)
{
if(!a[i]) break;
a[i]-=gather;
x=a[i]; gather+=x; ans+=x;
while(x)
{
x--;
if(sum0>) sum0=sum0+>>;
else break;
}
sum0++;
while(i<cnt && a[i+]-gather==)
{
sum0++;
a[++i]-=gather;
}
}
while(sum0>) ans++,sum0=sum0+>>;
cout<<ans;
}

考场上没注意有向图。。。。
一条道路如果能在上一组,那么肯定把它放在上一组最优
所以可以没加一条边,就判断当前1和n是否联通
判断方式: u-->v若现在u没有与1联通,就不管他
若u和v都与1联通了,那也不管他
若 u与1联通,而v 没有联通,那就再从v开始bfs
这样 每条边只会被访问一次
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream> using namespace std; #define N 200001
#define M 500001 int n; int front[N],nxt[M],to[M],tot; bool vis[N]; int use[N],cnt; queue<int>q; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} void add(int u,int v)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
} bool bfs(int s)
{
if(s==n) return true;
while(!q.empty()) q.pop();
q.push(s);
int now;
while(!q.empty())
{
now=q.front(); q.pop();
for(int i=front[now];i;i=nxt[i])
if(!vis[to[i]])
{
use[++cnt]=to[i];
if(to[i]==n) return true;
vis[to[i]]=true;
q.push(to[i]);
}
}
return false;
} int main()
{
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
int m;
read(n); read(m);
int u,v; int ans=;
vis[]=true;
for(int i=;i<=m;++i)
{
read(u); read(v);
if(vis[u] && !vis[v])
{
add(u,v);
vis[v]=true;
use[++cnt]=v;
if(bfs(v))
{
// printf("%d\n",i);
for(int i=;i<=cnt;++i) vis[use[i]]=false,front[use[i]]=;
front[]=;
cnt=tot=; ans++;
add(u,v);
if(u!=) use[++cnt]=u;
if(u==) vis[v]=true,use[++cnt]=v;
}
}
else if(!(vis[u] && vis[v])) add(u,v),use[++cnt]=u;
}
cout<<ans;
}
std思路:
结合了倍增的二分
如果用朴素的二分,会被m条边分m组卡成mm
先考虑1条边 能否使其联通,不能再考虑2条边,然后4条,8条……
若在2^p时 不能联通了,那么在2^p-1 ~ 2^p 范围内二分
这样时间复杂度是mlogm的

如果小兵的血量是1 2 3 4 5 ……
那么显然我们可以补到所有的兵
如果有相同血量的兵,那么只能补到其中的1个兵
所以我们要尽可能的把给出的兵的血量变成1 2 3 4 5 ……
一种可行的方案是 重复血量的兵 强制消耗代价使他 变成 血量更小 但血量不重复的兵
可以用栈记录之前没有的血量,每遇到一个重复的就用栈中的一个血量
例:1 2 4 4
扫到4的时候,之前没有血量3,3入栈
后面还是1个4,就让3出栈,即消耗代价 使4变成3
令c[i]=j 记录消耗代价后血量为i的兵实际上是原血量为j的兵
然后DP
dp[i][j] 表示到血量为i的兵,省下了j刀的最大补兵数
省下了j刀:就是先把兵的血量看成1,2,3,然后考虑每个兵砍或不砍。如果不砍,就可以省下一刀给以后用
所以如果不砍,状态转移为 dp[i][j]=dp[i-1][j-1]
如果砍的话,砍血量为i的兵要加上之前强制消耗的代价,所以dp[i][j]=dp[i-1][j+c[i]-i]+1
老鹿的攻击怎么体现的呢?
因为每次尽可能的让兵的血量变为1,2,3……
自己砍掉一个血量为1的兵,后面再老鹿的攻击下又产生了一个血量为1的兵
但实际DP时
从1开始枚举血量
血量为2时,实际血量为1,相当于 提高了 兵死亡时的血量
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream> using namespace std; #define N 1001 int f[N][N]; int a[N],c[N]; int cnt[N]; int st[N],top; int main()
{
freopen("cs.in","r",stdin);
freopen("cs.out","w",stdout);
int T,n,mx;
scanf("%d",&T);
while(T--)
{
memset(f,,sizeof(f));
memset(cnt,,sizeof(cnt));
memset(c,,sizeof(c));
top=mx=;
scanf("%d",&n);
for(int i=;i<=n;++i) scanf("%d",&a[i]),mx=max(mx,a[i]),cnt[a[i]]++;
sort(a+,a+n+);
for(int i=;i<=mx;i++)
if(!cnt[i]) st[++top]=i;
else
{
while(cnt[i]> && top ) c[st[top--]]=i,--cnt[i];
c[i]=i;
}
int ans=;
for(int i=;i<=mx;++i)
for(int j=;j<i;++j)
{
if(j) f[i][j]=f[i-][j-];
if(c[i] && j+c[i]-i<i) f[i][j]=max(f[i][j],f[i-][j+c[i]-i]+);
ans=max(ans,f[i][j]);
}
cout<<ans<<'\n';
}
}
2017 清北济南考前刷题Day 4 morning的更多相关文章
- 2017 清北济南考前刷题Day 7 afternoon
期望得分:100+100+30=230 实际得分:100+100+30=230 1. 三向城 题目描述 三向城是一个巨大的城市,之所以叫这个名字,是因为城市中遍布着数不尽的三岔路口.(来自取名力为0的 ...
- 2017 清北济南考前刷题Day 1 afternoon
期望得分:80+30+70=180 实际得分:10+30+70=110 T1 水题(water) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK出了道水 ...
- 2017 清北济南考前刷题Day 3 morning
实际得分:100+0+0=100 T1 右上角是必败态,然后推下去 发现同行全是必胜态或全是必败态,不同行必胜必败交叉 列同行 所以n,m 只要有一个是偶数,先手必胜 #include<cstd ...
- 2017 清北济南考前刷题Day 3 afternoon
期望得分:100+40+100=240 实际得分:100+40+100=240 将每个联通块的贡献乘起来就是答案 如果一个联通块的边数>点数 ,那么无解 如果边数=点数,那么贡献是 2 如果边数 ...
- 2017 清北济南考前刷题Day 4 afternoon
期望得分:30+50+30=110 实际得分:40+0+0=40 并查集合并再次写炸... 模拟更相减损术的过程 更相减损术,差一定比被减数小,当被减数=减数时,停止 对于同一个减数来说,会被减 第1 ...
- 2017 清北济南考前刷题Day 7 morning
期望得分:100+50+20=170 实际得分:10+50+20=80 1. 纸牌 题目描述 在桌面上放着n张纸牌,每张纸牌有两面,每面都写着一个非负整数.你的邪王真眼可以看到所有牌朝上的一面和朝下的 ...
- 2017 清北济南考前刷题Day 6 afternoon
期望得分:100+100+30=230 实际得分: 正解: 枚举最高的位,这一位m是1但实际用了0 然后剩余的低位肯定是 正数就用1,负数用0 考场思路:数位DP #include<cstdio ...
- 2017 清北济南考前刷题Day 6 morning
T1 贪心 10 元先找5元 20元 先找10+5,再找3张5 #include<cstdio> using namespace std; int m5,m10,m20; int main ...
- 2017 清北济南考前刷题Day 5 afternoon
期望得分:100+100+30=230 实际得分:0+0+0=30 T1 直接模拟 #include<cstdio> #include<iostream> using name ...
- 2017 清北济南考前刷题Day 5 morning
期望得分:100+100+0=200 实际得分: 坐标的每一位不是0就是1,所以答案就是 C(n,k) #include<cstdio> #include<iostream> ...
随机推荐
- week4a:个人博客作业
本周结对项目的要求: 黄金点游戏是一个数字小游戏,其游戏规则是: N个同学(N通常大于10),每人写一个0~100之间的有理数 (不包括0或100),交给裁判,裁判算出所有数字的平均值,然后乘以0.6 ...
- c# 判断两条线段是否相交(判断地图多边形是否相交)
private void button1_Click(object sender, EventArgs e) { //var result = intersect3(point1, point2, p ...
- KEIL C51代码优化详细分析
阅读了<单片机与嵌入式系统应用>2005年第10期杂志<经验交流>栏目的一篇文章<Keil C51对同一端口的连续读取方法>(原文)后,笔者认为该文并未就此问题进行 ...
- python下的Box2d物理引擎的配置
/******************************* I come back! 由于已经大四了,正在找工作 导致了至今以来第二长的时间内没有更新博客.向大家表示道歉 *********** ...
- [转帖] Oracle 关闭自动收集统计信息
--关闭自动统计信息 https://blog.csdn.net/royzhang7/article/details/51172556 明天再仔细看一下. select client_name,sta ...
- [C/C++] multimap查找一个key对应的多个value
在multimap中,同一个键关联的元素必然相邻存放.基于这个事实,就可以将某个键对应的值一一输出. 1.使用find和count函数.count函数求出某个键出现的次数,find函数返回一个迭代器, ...
- Js数组和字符串常用方法
字符串: 1.concat() – 将两个或多个字符的文本组合起来,返回一个新的字符串. 2.indexOf() – 返回字符串中一个子串第一处出现的索引.如果没有匹配项,返回 -1 . 3.ch ...
- Python实现双色球和大乐透摇奖
实现代码: # code by kadycui # 模块引用 import random def select(): print('\n') print('请选择彩票种类') print('双色球输入 ...
- 转载manifold learning一篇
我恨自己不干活儿,不过也没辙. 早晚要学习流形的,今天先转一篇文章,以后找不到就尿了. 我真羡慕数学系的人,╮(╯▽╰)╭. 发信人: Kordan (K&M), 信区: AI标 题: do ...
- 【题解】CF#896 D-Nephren Runs a Cinema
容易发现这些 vip 用户并没什么用,所以考虑枚举手持50元与100元的人共有多少个.设手持50元的人 \(a\) 个,手持100元的人 \(a - k\) 个,那么一共是 \(2*a - k\) 个 ...