A. 争夺圣杯

还是想说一下,这题是原题啊...想做的人可以戳codechef上的MTMXSUM(懒得贴链接了,套了个壳,不过正常人应该都能看得出来)

显然异或输出没什么奇怪的性质...

考虑一个元素a[x]在哪些区间中会成为最大值,我们可以用单调栈找出前面比这个元素大的第一个元素a[l],右边大的第一个元素a[r]。

考虑这个元素对每一长度的贡献,设p=x-l,q=r-x,那么对于区间[s,t],只有当l<s<=x,x<=t<r,只有这pq个区间最大值为a[x]。

那么考虑这些区间的长度,不妨设p<=q,那么可以根据区间长度跟p、q的关系来统计答案。

当1<=len<=p时,显然共有len个区间(因为x肯定要在区间内)。

当p<len<=q时,共有p个区间(因为左端点可以是l+1~x)

当q<len<=p+q-1时,共有p+q-len个([x-p+1,x-p+len]...[x+q-len,x+q-1])

好像是个区间加等差数列,随便前缀和维护一下。

具体地,例如[p,q]加1...q-p+1,这种事情我们用两个数组s1,s2来维护,s1[p...q]+=1,s2[p...q]-=p-1,这个前缀和搞搞。最后我们只要统计s1*i+s2就行了。

实现时l和r需要一边开一边闭(一边大于,一边大于等于),然后用单调栈维护即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll MOD=;
#define SZ 2333333
int n; ll hh[SZ];
#define gc getchar()
int gi_()
{
int s,c;
while(c=gc,c<||c>);
s=c-;
while(c=gc,c>=&&c<=) s=s*+c-;
return s;
}
#define gi gi_()
int L[SZ],R[SZ],ss[SZ],sn=;
ll q1[SZ],q2[SZ];
void add(ll& a,ll b)
{
a+=b; a%=MOD;
if(a<) a+=MOD;
}
int main()
{
n=gi;
for(int i=;i<=n;i++) hh[i]=gi;
for(int i=;i<=n;i++)
{
while(sn&&hh[ss[sn]]<hh[i]) --sn;
if(sn) L[i]=ss[sn]; ss[++sn]=i;
}
sn=;
for(int i=n;i>=;i--)
{
while(sn&&hh[ss[sn]]<=hh[i]) --sn;
if(sn) R[i]=ss[sn]; else R[i]=n+;
ss[++sn]=i;
}
for(int i=;i<=n;i++) hh[i]%=MOD;
for(int i=;i<=n;i++)
{
int l=L[i],r=R[i];
//1,min(i-l,r-i),max(i-l,r-i),(r-l)
add(q1[],hh[i]); add(q1[min(i-l,r-i)],-hh[i]);
add(q2[min(i-l,r-i)],min(i-l,r-i)*(ll)hh[i]%MOD);
add(q2[max(i-l,r-i)],(r-l)*(ll)hh[i]%MOD-min(i-l,r-i)*(ll)hh[i]%MOD);
add(q2[r-l],-(r-l)*(ll)hh[i]%MOD);
add(q1[max(i-l,r-i)],-hh[i]); add(q1[r-l],hh[i]);
}
int ans=;
for(int i=;i<=n;i++)
{
add(q1[i],q1[i-]); add(q2[i],q2[i-]);
ll orz=((q1[i]*i%MOD+q2[i]%MOD)%MOD+MOD)%MOD;
ans^=orz;
}
printf("%d\n",ans);
}

C. 果冻运输

好好的一道人类智慧提答(确实很好玩)硬生生搞成了暴搜题...

开始我写了个暴力,看看数据范围,心想:肯定搜不出来,就只写了个iddfs,然后把状态hash一下输出,目测找一找规律...

最后有几个点目测玩到了一些两三分的acceptable answer...其他点都搜出1分左右...旁边wwf大爷玩了5h提答,看起来过了十几个点,结果交上去都是两三分,结果总分还没我一堆1分高...惨啊

Q:没想到A*吗?

A:想啦,感觉估价函数非常蛋疼...谁知道设成同色联通块个数这种辣鸡玩意儿就行了...

Q:那也比傻逼暴搜好啊

A:惨啊

人类智慧做法可戳:http://dram.blog.uoj.ac/blog/1864(当然不是我写的

A*大法可戳:http://immortalco.blog.uoj.ac/blog/1854

有空去写写把...

A. Jakarta Skyscrapers

大意就是有一个集合,里面可以容纳正整数。开始里面只有a和b两个正整数,对于集合中两个数x和y,可以通过一次操作得到x-y并插入到集合中。(注意到集合中只能有正整数,所以必须x>=y)。求一些操作使得集合中包含正整数c。输出任意一种步数小于400的方案,如果不存在输出-1。

显然400步内不存在,那么肯定也不存在解了...

然后我们写个暴力,可以发现,A>=B时当且仅当C<=A且gcd(A,B)|C才有解,所以我们就可以判出-1。

(以下内容与题解一点关系都没有)

然后我们发现gcd不是这么写吗:

ll gcd(ll a,ll b)
{
while(b)
{
ll t=a%b; a=b; b=t;
}
return a;
}

那么假如我们自己实现了什么方法,能高效地在这个系统中实现取模和乘法,那么我们就这样做gcd,最后乘上C/gcd(A,B)就做完了。

接下来我们就说说怎么做吧。

减法:有啦 1次

加法:注意到A-(A-x-y)=x+y。 3次

乘法:注意到我们可以快速加 O(log)次

取模:被除数-商*除数 O(log)次

那么gcd的复杂度:

复杂度似乎挺科学?可是我这样写完只有70...看到一个点403次简直哭瞎。

后面用个map加了点记忆化就行啦。求hack

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <map>
using namespace std;
typedef long long ll;
#define SZ 666666
ll A,B,C,la[SZ],lb[SZ];
int ls=;
map<ll,bool> qd;
//O(1)
ll gminus(ll a,ll b)
{
if(!b) return a;
if(a==b) return ;
if(qd[a-b]) return a-b;
qd[a-b]=;
++ls; la[ls]=a; lb[ls]=b;
return a-b;
}
//O(3)
ll gadd(ll a,ll b)
{
if(a+b>=A) return A;
if(qd[a+b]) return a+b;
gminus(A,a);
gminus(A-a,b);
gminus(A,A-a-b);
return a+b;
}
ll ss[];
//O(log)
//不需要b在集合中
ll gmul(ll a,ll b)
{
if(qd[a*b]) return a*b;
ll tg=a*b;
ll cur=A,sn=;
while(b)
{
if(b&)
{
for(int i=;i<=sn;i++) gadd(ss[i],ss[i]); sn=;
cur=gminus(cur,a);
if(qd[tg-(A-cur)]) return gadd(tg-(A-cur),gminus(A,cur));
}
ss[++sn]=a; a<<=; b>>=;
}
return gminus(A,cur);
}
//O(log)
ll gmod(ll a,ll b)
{
if(a%b==) return ;
if(qd[a%b]) return a%b;
return gminus(a,gmul(b,a/b));
}
ll gcd(ll a,ll b)
{
while(b)
{
ll t=a%b; a=b; b=t;
}
return a;
}
void ggcd(ll a,ll b)
{
while(b)
{
ll t=gmod(a,b); a=b; b=t;
}
}
int main()
{
cin>>A>>B>>C; qd[A]=qd[B]=;
if(A<B) swap(A,B);
if(C%gcd(A,B)!=||C>A) {puts("-1"); return ;}
ll gcdd=gcd(A,B);
ggcd(A,B);
gmul(gcdd,C/gcdd);
cout<<ls<<"\n";
for(int i=;i<=ls;i++) cout<<la[i]<<" "<<lb[i]<<"\n";
}

C. 火车管理

建议不要用题解的做法,高级做法参见 http://wangyisong1996.blog.uoj.ac/blog/1866 (人傻看不懂官方题解

感觉说的十分清楚啊(虽然我也看不懂复杂度分析

两个傻逼错误一个调了一小时,一个调了两小时...大概就是标记到了叶子还往下pushdown标记就失踪了...

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
#include <iomanip>
using namespace std;
#define pb push_back
#define inf 1001001001
#define infll 1001001001001001001LL
#define FOR0(i,n) for(int (i)=0;(i)<(n);++(i))
#define FOR1(i,n) for(int (i)=1;(i)<=(n);++(i))
#define mp make_pair
#define pii pair<int,int>
#define ll long long
#define ld double
#define vi vector<int>
#define fi first
#define se second
#define SZ 1048588
#define S2 SZ*65
int an=,lc1[S2],rc1[S2],vs[S2];
int newn(int x) {return vs[++an]=x, an;}
int join(int a,int b)
{
//cout<<"JOIN"<<a<<","<<b<<"\n";
if(a&&b);else return a^b;
int s=newn(vs[a]);
lc1[s]=a; rc1[s]=b;
return s;
}
int delf(int x)
{
if(!x||!lc1[x]) return ;
else if(lc1[lc1[x]])
{
int g=++an;
lc1[g]=delf(lc1[x]);
rc1[g]=rc1[x];
vs[g]=vs[lc1[g]];
return g;
}
else return rc1[x];
}
int ls[SZ],rs[SZ],sum[SZ],tag[SZ],M=,M2=M+M;
void tagit(int x,int vid)
{
if(!x||x>M2) return;
sum[x]=(rs[x]-ls[x]+)*vs[vid];
tag[x]=join(vid,tag[x]); //md这一句调了我一个小时
}
void pd(int x)
{
if(!x||x>M2||!tag[x]||x+x>M2/*wtf*/) return;
tagit(x+x,tag[x]);
tagit(x+x+,tag[x]);
tag[x]=;
}
void upd(int x)
{
//pd(x+x); pd(x+x+1);
sum[x]=sum[x+x]+sum[x+x+];
}
void popt(int x)
{
if(!x||x>M2||!tag[x]) return;
sum[x]-=vs[tag[x]];
tag[x]=delf(tag[x]);
if(tag[x]) sum[x]+=vs[tag[x]];
}
void build()
{
for(int i=;i<=M;i++) ls[i+M]=rs[i+M]=i;
for(int i=M-;i>=;i--) ls[i]=ls[i+i], rs[i]=rs[i+i+];
}
void push(int x,int l,int r,int ns)
{
if(l>r||!x||x>M2) return;
if(ls[x]==l&&rs[x]==r) {tagit(x,ns); return;}
pd(x);
int m=ls[x]+rs[x]>>;
push(x+x,l,min(r,m),ns);
push(x+x+,max(m+,l),r,ns);
upd(x);
}
void pop(int x,int p)
{
if(!x||x>M2||p<ls[x]||p>rs[x]) return;
if(ls[x]==rs[x]) {popt(x); return;}
pd(x); pop(x+x,p); pop(x+x+,p); upd(x);
}
int query(int x,int l,int r)
{
if(l>r||!x||x>M2) return ;
if(ls[x]==l&&rs[x]==r) return sum[x];
pd(x);
int m=ls[x]+rs[x]>>,ans=;
ans+=query(x+x,l,min(r,m));
ans+=query(x+x+,max(m+,l),r);
upd(x);
return ans;
}
int main()
{
build();
int n,m,ty,lans=;
scanf("%d%d%d",&n,&m,&ty);
while(m--)
{
int tp,a,b,c;
scanf("%d",&tp);
if(tp!=)
{
scanf("%d%d",&a,&b);
a=(a+lans*ty)%n+; b=(b+lans*ty)%n+;
if(a>b) swap(a,b);
}
else
{
scanf("%d",&a);
a=(a+lans*ty)%n+;
}
if(tp==) printf("%d\n",lans=query(,a,b));
else if(tp==) pop(,a);
else scanf("%d",&c), push(,a,b,newn(c));
//if(m&127);else cerr<<m<<"\n";
}
}

最后似乎是rank40卡线银牌?反正涨了很多rating还是很高兴的(因为之前rating太低辣)

剩下的题解等看懂了再来补...

UNR #1 题解的更多相关文章

  1. #386. 【UNR #3】鸽子固定器

    #386. [UNR #3]鸽子固定器 题目链接 官方题解 分析: 神奇的做法+链表. 首先按照大小排序. 对于小于选择小于m个物品的时候,这个m个物品一定是一段连续的区间.因为,如果中间空着一个物品 ...

  2. 【UOJ#310】【UNR#2】黎明前的巧克力(FWT)

    [UOJ#310][UNR#2]黎明前的巧克力(FWT) 题面 UOJ 题解 把问题转化一下,变成有多少个异或和为\(0\)的集合,然后这个集合任意拆分就是答案,所以对于一个大小为\(s\)的集合,其 ...

  3. 【UOJ#308】【UNR#2】UOJ拯救计划

    [UOJ#308][UNR#2]UOJ拯救计划 题面 UOJ 题解 如果模数很奇怪,我们可以插值一下,设\(f[i]\)表示用了\(i\)种颜色的方案数. 然而模\(6\)这个东西很有意思,\(6=2 ...

  4. 【UOJ#390】【UNR#3】百鸽笼(动态规划,容斥)

    [UOJ#390][UNR#3]百鸽笼(动态规划,容斥) 题面 UOJ 题解 发现这就是题解里说的:"火山喷发概率问题"(大雾 考虑如果是暴力的话,你需要记录下当前每一个位置的鸽笼 ...

  5. 【UOJ#389】【UNR#3】白鸽(欧拉回路,费用流)

    [UOJ#389][UNR#3]白鸽(欧拉回路,费用流) 题面 UOJ 题解 首先第一问就是判断是否存在一条合法的欧拉回路,这个拿度数和连通性判断一下就行了. 第二问判断转的圈数,显然我们只需要考虑顺 ...

  6. 【UOJ#388】【UNR#3】配对树(线段树,dsu on tree)

    [UOJ#388][UNR#3]配对树(线段树,dsu on tree) 题面 UOJ 题解 考虑一个固定区间怎么计算答案,把这些点搞下来建树,然后\(dp\),不难发现一个点如果子树内能够匹配的话就 ...

  7. 【UOJ#386】【UNR#3】鸽子固定器(贪心)

    [UOJ#386][UNR#3]鸽子固定器(贪心) 题面 UOJ 题解 一个不难想到的暴力做法是把东西按照\(s\)排序,这样子我们枚举极大值和极小值,那么我们选择的一定是这一段之间\(v\)最大的那 ...

  8. Educational Round 64 题解

    前言: 这场太难了……我一个紫名只打出两题……(虽说感觉的确发挥不够好) 一群蓝绿名的dalao好像只打了两题都能升分的样子…… 庆幸的是最后A出锅然后unr了>///< 写一波题解纪念这 ...

  9. 「UNR#1」奇怪的线段树

    「UNR#1」奇怪的线段树 一道好题,感觉解法非常自然. 首先我们只需要考虑一次染色最下面被包含的那些区间,因为把无解判掉以后只要染了一个节点,它的祖先也一定被染了.然后发现一次染色最下面的那些区间一 ...

随机推荐

  1. Android Contextual Menus之二:contextual action mode

    Android Contextual Menus之二:contextual action mode 接上文:Android Contextual Menus之一:floating context me ...

  2. Android二维码识别 开源项目ZXing的编译

    Android二维码识别 开源项目ZXing的编译 Android端的条形码/二维码识别功能 因为手机端的输入不是很方便,所以条形码/二维码的扫描是一种很有效的解决手段. 比较流行的手机应用中,常用的 ...

  3. block 页面传值小结

    我以自己项目中的一个模块为例,首先有两个页面,第一个页面为显示城市页面,第二个页面为选择要使用block传的值(城市名). 第一个页面中的显示控件: //自定义左部定位视图 self.locView ...

  4. XML解析之SAX详解

    XML解析之SAX详解 本文属于作者原创 http://www.cnblogs.com/ldnh/ XML解析的五个步骤 1.打开文档 (void)parserDidStartDocument:(NS ...

  5. 【原+转】用CMake代替makefile进行跨平台交叉编译

    在开始介绍如何使用CMake编译跨平台的静态库之前,先讲讲我在没有使用CMake之前所趟过的坑.因为很多开源的程序,比如png,都是自带编译脚本的.我们可以使用下列脚本来进行编译: ./configu ...

  6. 列式存储(二)JFinal如何处理从前台传回来的二维数组

    上一篇说到了列式存储,这一篇说它的存储问题,将每个模块的所有属性字段单独存到一张表中,新增页面时,所有的字段都去数据库请求,这样多个模块的新增功能可以共用一个jsp.由于每个模块的字段个数不一样,有的 ...

  7. 同步时间linux

    针对对时间要求精确度高的服务器 1.安装时间服务器yum install ntp 2.同步时间ntpdate time.nist.gov 3.设置计划任务每隔10分钟同步一次 */10 * * * * ...

  8. (视频) 《快速创建网站》2.1 在Azure上创建网站及网站运行机制

    现在让我们开始一天的建站之旅. 本文是<快速创建网站>系列的第2篇,如果你还没有看过之前的内容,建议你点击以下目录中的章节先阅读其他内容再回到本文. 访问本系列目录,请点击:http:// ...

  9. 面试题整理:C#(二)

    1.类,接口的区别 从定义的角度类描述一个实体,包括状态.属性和动作接口定义一类动作,没有实现,也没有状态信息从程序的角度接口是函数声明:类是函数实现接口可以有属性,不能有字段一个子类只能继承一个父类 ...

  10. spring + spring mvc + mybatis + react + reflux + webpack Web工程例子

    前言 最近写了个Java Web工程demo,使用maven构建: 后端使用spring + spring mvc + mybatis: 前端使用react + react-router+ webpa ...