[雅礼NOIP2018集训 day3]
考试的时候刚了T1两个小时线段树写了三个子任务结果发现看错了题目,于是接下来一个半小时我自闭了
result=历史新低
这告诉我们,打暴力要端正态度,尤其是在发现自己之前出锅的情况下要保持心态的平和,不能和今天的比赛一样后面差不多直接弃疗
T1:
题意就是我们要做多次倒三角的区间加,最后统计全部的异或和。不幸的是当我看到空间限制512MB的时候就直接暴力上线段树了,凉心出题人
正解是很巧妙的二维前缀和做法
考虑我们暴力怎么做--对倒三角的每一行差分,最后统计一次,这样的复杂度是$O(nq)$的
这个时候可以发现每一次倒三角我们改变的差分序列是可以二维差分优化的。其实就是对三角的竖着的直角边和那条斜边在维护差分数组,最后再统计答案就好了
其他的做法不会啊,果然还是太弱
- #include<algorithm>
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<time.h>
- using namespace std;
- typedef long long ll;
- const int N=3e3+;
- ll n,q;
- ll a[N][N],b[N][N],c[N][N],d[N][N],e[N][N];
- inline ll read()
- {
- char ch=getchar();
- ll s=,f=;
- while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
- while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
- return s*f;
- }
- int main()
- {
- freopen("u.in","r",stdin);
- freopen("u.out","w",stdout);
- //double st=clock();
- n=read();q=read();
- while (q--)
- {
- ll r=read(),c=read(),l=read(),s=read();
- a[r][c]+=s;a[r+l][c]-=s;
- b[r-c+n-][r]-=s;b[r-c+n-][r+l]+=s;
- }
- for (int i=;i<=n;i++)
- for (int j=;j<=n;j++)
- {
- c[i][j]=c[i-][j]+a[i][j];
- d[i][j]=d[i-][j-]+b[i-j+n][i];
- e[i][j]=e[i][j-]+c[i][j]+d[i][j];
- }
- /*for (int i=1;i<=n;i++)
- {
- for (int j=1;j<=n;j++)
- printf("%d ",c[i][j]+d[i][j]);
- printf("\n");
- }*/
- //printf("\n");
- ll ans=;
- for (int i=;i<=n;i++)
- for (int j=;j<=n;j++) ans^=e[i][j];
- /*for (int i=1;i<=n;i++)
- {
- for (int j=1;j<=n;j++) printf("%d ",e[i][j]);
- printf("\n");
- }*/
- printf("%lld\n",ans);
- //double ed=clock();
- //printf("%lf\n",ed-st);
- }
T2:
数据范围好像就是给你状压DP的,状态分别是当前还剩下的球(一个0/1序列)和剩下球的个数(这里有个坑点,不能直接通过0/1序列记忆化,因为最高位可能是0,这样可能出现长度不同但是0/1序列相同的两个状态)
我们数组记忆化肯定是不行的,那么大的就只好开map了。鉴于上述的坑点,看代码注释了解如何避免吧
所谓最优策略,其实就是状态转移的时候取max就好
还有就是关于那个erase函数,删掉一个球,相当于在一个二进制数里面去掉一位。设去掉的二进制位为k,笔者的思路就是把0-k-1先取出来(预处理111...这样的数字&一下就好了),再把原来的数后面变成0(注意0的个数要比原来的位数少1,因为有一位被去掉了)
然后这题好像就A了,考场上像个傻叉一样的写搜索,关键是之前的1分暴力写完了没打return 0,输出两个答案的我彻底凉凉了,22分暴力都没有拿到
- #include<algorithm>
- #include<cstring>
- #include<cstdio>
- #include<iostream>
- #include<map>
- using namespace std;
- const int N=;
- int n,k;
- int pre[N];
- namespace calc
- {
- const int M=;
- double a[<<M+];
- map <int,double> p[N];
- void init()
- {
- for (int i=;i<<<M+;i++) a[i]=-;
- }
- bool count(int bit,int len)
- {
- if (len<=M) return a[<<len|bit]!=-;//坑点处理在这儿,看到那个|没有?std太伟大了
- else return p[len].count(bit);
- }
- double &find(int bit,int len)
- {
- if (len<=M) return a[<<len|bit];
- else return p[len][bit];
- }
- }
- int erase(int bit,int i)
- {
- return (bit&pre[i-])|((bit>>(i+))<<i);
- }
- double dfs(int bit,int len)
- {
- if (len<=k) return ;
- if (calc::count(bit,len)) return calc::find(bit,len);//记忆化
- double &res=calc::find(bit,len);
- res=;
- for (int i=,j=len-;i<=j;++i,--j)
- {
- if (i<j) res+=max(dfs(erase(bit,i),len-)+(bit>>i&),dfs(erase(bit,j),len-)+(bit>>j&))*;//*2是因为正的第i个,反的第len-i+1个也是这个位置
- else res+=dfs(erase(bit,i),len-)+(bit>>i&);
- }
- return res/=len;//别忘了/len
- }
- int main()
- {
- //freopen("v.in","r",stdin);
- //freopen("v.ans","w",stdout);
- scanf("%d%d",&n,&k);
- char ch[N];
- scanf("%s",ch);
- calc::init();
- pre[]=;
- for (int i=;i<N;i++) pre[i]=pre[i-]|(<<i);
- int bit=;
- k=n-k;
- for (int i=;i<n;i++)
- {
- bit|=(ch[i]=='W')<<i;
- }
- printf("%.10lf\n",dfs(bit,n));
- return ;
- }
T3:
有两个需要明确的性质
1.不要变的边我们不变,因为变了我们还要至少花费一次代价把它变回来
2.一棵树里变了的边的条数就是在这些边覆盖的点集中奇数度数点的个数/2(度数是翻转的边带来的)。这个好像挺显然的,因为一条翻转的边只会给两个端点带来奇数的度数,中间的都是偶数的度数
考虑dp,dp[x][0/1]表示节点x与父亲的边是否翻转,最少的奇数点的个数和翻转的总长度(我们的dp数组存的这样的结构体)
发现目标是在最少的奇数点的基础上最小化翻转的总长度,也就是前者优先,于是我们用pair
考虑如何转移
设x与父亲的边的类型是type(if (d==2) type=2 else type=c^d)
如果type==1||type==2的话,dp[x][0]显然可以设成inf了,我们只能转移dp[x][1]。设tmp0表示仅仅考虑x的子树,当前点x不是路径端点的最小代价(注意x可能是被一条路径经过);tmp1表示仅仅考虑x的子树,当前点是路径端点的最小代价。这两个如何计算参见代码。dp[x][1]=max((tmp0.fi+1,tmp0.se+1),(tmp1.fi,tmp1.se+1))
还有就是type==0||type==2,这种情况也差不多,不理解参考代码吧
- #include<algorithm>
- #include<cstdio>
- #include<cstring>
- #include<iostream>
- #include<vector>
- #define pii pair<int,int>
- using namespace std;
- const int N=1e5+;
- const int inf=1e9+;
- int n;
- vector <pii> mp[N];
- pii dp[N][];
- inline int read()
- {
- char ch=getchar();
- int s=,f=;
- while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
- while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
- return s*f;
- }
- pii operator + (pii a,pii b){return make_pair(a.first+b.first,a.second+b.second);}
- void dfs(int x,int fa,int type)
- {
- pii tmp0(,),tmp1(inf,inf);//tmp0是不以它为断电答案,tmp1是以它为端点的最小答案
- for (int i=;i<mp[x].size();i++)
- {
- int y=mp[x][i].first;
- if (y==fa) continue;
- dfs(y,x,mp[x][i].second);
- pii nxt0,nxt1;
- nxt0=min(tmp0+dp[y][],tmp1+dp[y][]);
- nxt1=min(tmp0+dp[y][],tmp1+dp[y][]);
- tmp0=nxt0;tmp1=nxt1;
- }
- if (type==||type==)
- {
- dp[x][]=min(tmp0,make_pair(tmp1.first+,tmp1.second));
- }
- else dp[x][]=make_pair(inf,inf);
- if (type==||type==)
- {
- dp[x][]=min(make_pair(tmp1.first,tmp1.second+),make_pair(tmp0.first+,tmp0.second+));
- }
- else dp[x][]=make_pair(inf,inf);
- }
- int main()
- {
- n=read();
- for (int i=;i<n;i++)
- {
- int a=read(),b=read(),c=read(),d=read();
- if (d!=) d=c^d;
- mp[a].push_back(make_pair(b,d));
- mp[b].push_back(make_pair(a,d));
- }
- dfs(,-,);
- printf("%d %d\n",dp[][].first/,dp[][].second);
- return ;
- }
[雅礼NOIP2018集训 day3]的更多相关文章
- [雅礼NOIP2018集训] day6
打满暴力好像是一种挑战,已经连续几天考试最后一个小时自闭了,因为自以为打完了暴力,然而,结果往往差强人意 大概是考试的策略有些问题 T1: 我们设$g[x]$为在x时取小于等于m个物品的最大价值,下面 ...
- [雅礼NOIP2018集训 day4]
感觉状态极差啊,今天居然爆零了 主要是以下原因: 1.又是T1看错题肝了两个小时,发现题意理解错误瞬间心态爆炸 2.T2交错了文件名 3.T3暴力子任务和正解(假的)混在一起,输出了两个答案 都想为自 ...
- [雅礼NOIP2018集训 day1]
现在才来填坑,之后还要陆续补其他几天的,可能前几天真的太颓了 T1: 题目大意:给定一个长度为n的序列,m次询问每次询问给出l,r,询问区间l到r的元素在模k意义下的最大值 数据范围当然是你暴力写不过 ...
- 雅礼 noip2018 模拟赛 day3 T3
典型树形dp 这里,我们应该看到一些基本性质: ①:如果这个边不能改(不是没有必要改),我们就不改,因为就算改过去还要改回来,显然不是最优的 注意:"不能改"是指边的性质和要求的相 ...
- 雅礼 noip2018 模拟赛day3 T2
典型的状压思想 设0表示黑球,1表示白球,用一串01序列代表剩下的球的状态,记f[i]表示在i状态下取球的最大期望 那么可以利用记忆化搜索更新,每一层枚举可能拿走的球然后向下搜索,同时记忆化即可 在状 ...
- [雅礼NOIP集训 2017] number 解题报告 (组合数+二分)
题解: 令$S(i)={i+1,i+2,...,i<<1}$,f(i,k)表示S(i)中在二进制下恰好有k个1的数的个数 那么我们有$f(i,k)=\sum_{x=1}^{min(k,p) ...
- LOJ_6045_「雅礼集训 2017 Day8」价 _最小割
LOJ_6045_「雅礼集训 2017 Day8」价 _最小割 描述: 有$n$种减肥药,$n$种药材,每种减肥药有一些对应的药材和一个收益. 假设选择吃下$K$种减肥药,那么需要这$K$种减肥药包含 ...
- 雅礼集训【Day6-1】字符串
雅礼集训[Day6-1]字符串 假设我们有串\(a\),我们设\(a'\)为\(a\)翻转后按为取反过后的串. 我们只考虑前一半的,长为\(m\)的串.如果前半截匹配了\(a\)或者\(a'\),则\ ...
- 「雅礼集训 2017 Day7」事情的相似度
「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...
随机推荐
- angularjs1-过滤器
<!DOCTYPE html> <html> <body> <header> <meta http-equiv="Content-Typ ...
- 0x35 高斯消元与线性空间
颓了十天回来做题果然…… 感觉还是很有收获的,这两以前都没学过 bzoj1013: [JSOI2008]球形空间产生器sphere poj1830(upd) 之前做得很烂还被 D飞*2 了..重做一次 ...
- checkbox复选框和div click事件重叠,点击div后复选框也被选中,同时改变div颜色,否则则不选中
checkbox复选框和div click事件重叠,点击div后复选框也被选中,同时改变div颜色,否则则不选中 <!DOCTYPE html> <html lang=" ...
- redis简单的事务
Redis与 mysql事务的对比 占位 Mysql Redis 开启 start transaction muitl 语句 普通sql 普通命令 失败 rollback 回滚 discard 取消 ...
- DateUtil时间工具类
package utils; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util. ...
- Android Studio配置GreenDAO 3.2.0和使用方法
我相信,在平时的开发过程中,大家一定会或多或少地接触到SQLite.然而在使用它时,我们往往需要做许多额外的工作,像编写SQL语句与解析查询结果等.所以,适用于Android ORM框架也就孕育而生了 ...
- 。net内存优化
1.尽量减少和避免不必要的对象 2.优化算法和数据结构 3.采用非托管代码或者模块编写数据处理逻辑 4.NET应用程序的内存一定程度上受垃圾回收的影响.并指出,一些数据结构如List,系统会分配多余的 ...
- ZBrush设计制作小怪兽并用KeyShot渲染
ZBrush为电影制作设计独特的生物概念重点向大家介绍了概念设计师Ian Joyner使用ZBrush®3D图形绘制软件雕刻面对镜头咆哮的生物半身像的具体过程,ZBrush创建好模型之后,要想让角色更 ...
- struts 中数据处理的3中方式
方式一: 获取servletapi中的对象 方式二: struts中封装的对象 方式三: 实现接口 方式一和方式二的区别 方式一需要额外引入包或者是方式二实现不了的功能,比如:获取url 因为方式二只 ...
- ES6 学习6 数组的扩展
本章学习要点: 扩展运算符 Array.from() Array.of() 数组实例的 copyWithin() 数组实例的 find() 和 findIndex() 数组实例的 fill() 数组实 ...