AtCoder Grand Contest 015题解
\(A\)
找到能达到的最大的和最小的,那么中间任意一个都可以被表示出来
typedef long long ll;
int n,a,b;ll res;
int main(){
scanf("%d%d%d",&n,&a,&b);
if(a>b||n==1&&a!=b)return puts("0"),0;
res=(a+b+1ll*(n-2)*b)-(a+b+1ll*(n-2)*a)+1;
printf("%lld\n",res);
return 0;
}
\(B\)
分别算出需要走一次的对数和两次的对数即可
typedef long long ll;
const int N=1e5+5;
char s[N];int n;ll res,sum;
int main(){
scanf("%s",s+1),n=strlen(s+1);
fp(i,1,n)sum+=(s[i]=='U'?n-i:i-1);
res=(1ll*n*(n-1)-sum)*2+sum;
printf("%lld\n",res);
return 0;
}
\(C\)
不难发现蓝点构成了一个类似树的东西,那么连通块个数就是总点数减去边数,分别维护一下就好了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2005;
char mp[N][N];int r[N][N],c[N][N],s[N][N],n,m,q;
inline int qs(R int x,R int y,R int xx,R int yy){
return s[xx][yy]-s[x-1][yy]-s[xx][y-1]+s[x-1][y-1];
}
inline int qr(R int x,R int y,R int xx,R int yy){
return r[xx][yy]-r[x-1][yy]-r[xx][y-1]+r[x-1][y-1];
}
inline int qc(R int x,R int y,R int xx,R int yy){
return c[xx][yy]-c[x-1][yy]-c[xx][y-1]+c[x-1][y-1];
}
int main(){
scanf("%d%d%d",&n,&m,&q);
fp(i,1,n){
scanf("%s",mp[i]+1);
fp(j,1,m)s[i][j]=(mp[i][j]=='1')+s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
fp(i,1,n)fp(j,1,m-1){
r[i][j]=r[i-1][j]+r[i][j-1]-r[i-1][j-1]+(mp[i][j]=='1'&&mp[i][j+1]=='1');
}
fp(i,1,n-1)fp(j,1,m){
c[i][j]=c[i-1][j]+c[i][j-1]-c[i-1][j-1]+(mp[i][j]=='1'&&mp[i+1][j]=='1');
}
for(R int x,y,xx,yy;q;--q){
scanf("%d%d%d%d",&x,&y,&xx,&yy);
printf("%d\n",qs(x,y,xx,yy)-qr(x,y,xx,yy-1)-qc(x,y,xx-1,yy));
}
return 0;
}
\(D\)
首先如果\(A=B\)答案为\(1\),所以我们假设\(B>A\)
找到第一个\(A,B\)二进制意义下不同的位\(r\),那么前面的位都是没有用的可以删掉
然后我们把数分成两个集合\(X:[A,2^r),Y:[2^r,B]\)
设\(k\)为\(B\)中第一个小于\(r\)且为\(1\)的二进制位,则有
只用\(X\)能表示出\([A,2^r)\)(直接选对应的数),且只能表示出这些(能表示出的最小的数为\(A\),最大的数为\(2^r-1\))
只用\(Y\)能且只能表示出\([2^r,2^r+2^{k+1}-1]\)(因为每一个\(2^r+2^i\)(i\leq k)都必定存在于\(Y\)中)
同时用\(X\)和\(Y\)能表示出\([2^r+A,2^{r+1}-1]\)(直接选\(2^r\)和一个\(X\)中的数),且只能表示出这些(同上)
那么我们直接加上\([A,2^{r+1}-1]\),然后判一下\(2^r+2^{k+1}-1\)和\(2^r+A\)的大小就好了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
ll a,b,res;
int main(){
scanf("%lld%lld",&a,&b);
if(a==b)return puts("1"),0;
R int r,k;
for(r=59;(a>>r&1)==(b>>r&1);--r);
a&=(1ll<<(r+1))-1,b&=(1ll<<(r+1))-1;
res=(1ll<<(r+1))-a;
for(k=r-1;(~k)&&(b>>k&1^1);--k);
if(a>(1ll<<(k+1)))res-=a-(1ll<<(k+1));
printf("%lld\n",res);
return 0;
}
\(E\)
我应该就是那种数据结构做傻了的人……
先说一下题解的做法再说我的吧
首先当时间足够久之后,所有数的相对顺序肯定是按\(v\)排序之后的相对顺序,记\(id_i\)表示按\(v\)排序之后\(i\)处在的位置
我们假设一开始时只有\(i\)是被选中的,那么对于一个\(x_j<x_i\)且\(v_j>v_i\)的点\(j\),肯定会经过\(i\)使得自己被选中,而且按\(v\)排序之后所有在\(i,j\)之间的点都会被选中
我们对于每一个\(i\),计算出最大的\(id_j\)且\(x_j<x_i\),记为\(r_i\),那么所有\([id_i,id_{r_i}]\)之间的点都会被选。同理可定义\(l_i\)。容易发现\(l,r\)都是单调不降的
那么问题转化成给定\(n\)个区间且保证左右端点单调不降,选择其中若干个使得覆盖\([1,n]\),那么我们记\(f_i\)表示\([1,i]\)都已经被覆盖的方案数,前缀和优化转移即可
我的做法在后面
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
const int N=2e5+5;
struct node{
int x,v;
inline bool operator <(const node &b)const{return x<b.x;}
}a[N];
int id[N],l[N],r[N],f[N],n;
inline bool cmp(const int &x,const int &y){return a[x].v<a[y].v;}
int main(){
scanf("%d",&n);
fp(i,1,n)scanf("%d%d",&a[i].x,&a[i].v),id[i]=i;
sort(a+1,a+1+n),sort(id+1,id+1+n,cmp);
fp(i,1,n)l[id[i]]=r[id[i]]=i;
fp(i,2,n)cmax(r[i],r[i-1]);
fd(i,n-1,1)cmin(l[i],l[i+1]);
f[0]=1;
for(R int i=1,j=0,sum=1;i<=n;++i){
while(j<l[i]-1)sum=dec(sum,f[j++]);
upd(f[r[i]],sum),upd(sum,sum);
}
printf("%d\n",f[n]);
return 0;
}
首先先按\(x\)排序,对于一个\(i\),如果它一开始被选就肯定会被选,否则设\(las\)和\(nxt\)分别为前一个被选的和后一个被选的,设\(l\)表示\([1,las]\)中所有速度的最大值,\(r\)表示\([nxt,n]\)中所有速度的最小值,那么\(i\)不会被选当且仅当\(i\in [l,r]\)(也就是说既不可能有数从前面赶上它导致它被选,它也不可能赶上一个后面的数导致自己被选)
我们设\(las_i\)表示当\(i\)选了之后,最大的\(j\)使得\(j\)被选之后\([j+1,i-1]\)这个区间内每一个数都会被选,那么可以二分,判断的时候在主席树上判一下就行了
然后设\(f[i]\)表示\(i\)必须选的方案数,那么上一个被选的可以是\([las[i],i-1]\)中的任意一个数,前缀和优化一下就好了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
inline int max(R int x,R int y){return x>y?x:y;}
inline int min(R int x,R int y){return x<y?x:y;}
const int N=2e5+5,M=N*35,inf=0x3f3f3f3f;
int ls[M],rs[M],sz[M],rt[N],nd;
void ins(int &p,int q,int l,int r,int x){
p=++nd,ls[p]=ls[q],rs[p]=rs[q],sz[p]=sz[q]+1;
if(l==r)return;int mid=(l+r)>>1;
x<=mid?ins(ls[p],ls[q],l,mid,x):ins(rs[p],rs[q],mid+1,r,x);
}
int query(int p,int q,int l,int r,int ql,int qr){
if(!(sz[p]-sz[q])||ql<=l&&qr>=r)return sz[p]-sz[q];
int mid=(l+r)>>1,res=0;
if(ql<=mid&&query(ls[p],ls[q],l,mid,ql,qr))return 1;
if(qr>mid&&query(rs[p],rs[q],mid+1,r,ql,qr))return 1;
return 0;
}
struct node{
int x,v;
inline bool operator <(const node &b)const{return x<b.x;}
}a[N];
int b[N],las[N],f[N],mx[N],mn[N],sum[N];
int n;
inline int find(R int pos){
R int l=0,r=pos-1,ans=pos-1,mid;
while(l<=r){
mid=(l+r)>>1;
if(mid==pos-1||mx[mid]+1>mn[pos]-1||!query(rt[pos-1],rt[mid],1,n,mx[mid]+1,mn[pos]-1))
ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d",&n);
fp(i,1,n)scanf("%d%d",&a[i].x,&a[i].v),b[i]=a[i].v;
sort(a+1,a+1+n),sort(b+1,b+1+n);
fp(i,1,n){
a[i].v=lower_bound(b+1,b+1+n,a[i].v)-b;
ins(rt[i],rt[i-1],1,n,a[i].v);
}
mx[0]=0;fp(i,1,n)mx[i]=max(mx[i-1],a[i].v);
mn[n+1]=inf;fd(i,n,1)mn[i]=min(mn[i+1],a[i].v);
fp(i,1,n+1)las[i]=find(i);
f[0]=sum[0]=1;
fp(i,1,n+1){
f[i]=dec(sum[i-1],(las[i]?sum[las[i]-1]:0));
sum[i]=add(sum[i-1],f[i]);
}
printf("%d\n",f[n+1]);
return 0;
}
\(F\)
神仙结论题
以下设\(f(x,y)\)表示\(x,y\)辗转相除的步数且默认\(x<y\)
首先我们考虑斐波那契数列,并定义\(F[0]=F[1]=1\),容易发现\(f(F[i],F[i+1])=i\)且对于所有\(f(a,b)=i\),有\(a\geq F[i],b\geq F[i+1]\)。所以第一个问题很简单就能搞出来
我们定义一个数对\(f(a,b)\)是好的,当且仅当不存在\(c<a,d<b\)且\(f(c,d)>f(a,b)\),那么只有好的数对会对答案有贡献
我们定义一个数对\(f(a,b)\)是优秀的,当且仅当若\(f(a,b)=k\),则\(a,b\leq F[k+2]+F[k-1]\)
有一个结论:任何一个好的数对经过一次辗转相除之后会变成一个优秀的数对
考虑反证法,假设\(a=y,b=py+x\),且\(f(a,b)=k+1\),那么辗转相除之后变成\((x,y)\),如果\((x,y)\)不是优秀的数对,则\(y>F[k+2]+F[k-1]\),从而有
&a=y>F[k+2]\\
&x>F[k]\\
&b=py+x\geq y+x>F[k+2]+F[k-1]+F[k]=F[k+3]\\
\end{aligned}
\]
所以存在\(c=F[k+2],d=F[k+3]\),使得\(f(c,d)>f(a,b)\),这与\((a,b)\)是好的数对不符
这样我们就证明了任意一个好的数对经过一次辗转相除之后会变成一个优秀的数对,而优秀的数对并不会太多(据说满足\(f(a,b)=k\)的优秀的数对个数是\(O(k)\)?不过我并不会证明)
那么我们打表把所有\(f(a,b)=k\)的优秀的数对打出来就好了,询问的时候用优秀的数对去生成好的数对即可
//quming
#include<bits/stdc++.h>
#define R register
#define pb emplace_back
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
typedef long long ll;
const int N=105,M=90;
struct node{
ll x,y;
inline node(R ll xx,R ll yy):x(xx),y(yy){}
};vector<node>g[N];
ll f[N],n,m,T,res,cnt;
int main(){
f[0]=f[1]=1;fp(i,2,M)f[i]=f[i-1]+f[i-2];
g[1].pb(node(1,2)),g[1].pb(node(1,3)),g[1].pb(node(1,4));
fp(i,1,M-3){
for(auto v:g[i]){
R ll x=v.y,y=v.x+x;
while(y<=f[i+3]+f[i])g[i+1].pb(node(x,y)),y+=x;
}
}
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&n,&m);if(n>m)swap(n,m);
for(cnt=1;f[cnt+1]<=n&&f[cnt+2]<=m;++cnt);
if(cnt==1){printf("%lld %lld\n",cnt,n*m%P);continue;}
res=0;
for(auto v:g[cnt-1]){
R ll x=v.x,y=v.y;
if(y<=n)res+=(m-x)/y%P;
if(y<=m)res+=(n-x)/y%P;
res%=P;
}
printf("%lld %lld\n",cnt,res);
}
return 0;
}
AtCoder Grand Contest 015题解的更多相关文章
- AtCoder Grand Contest 015 题解
A - A+...+B Problem 常识 Problem Statement Snuke has N integers. Among them, the smallest is A, and th ...
- AtCoder Grand Contest 017 题解
A - Biscuits 题目: 给出 \(n\) 个物品,每个物品有一个权值. 问有多少种选取方式使得物品权值之和 \(\bmod\space 2\) 为 \(p\). \(n \leq 50\) ...
- AtCoder Grand Contest 015 C - Nuske vs Phantom Thnook
题目传送门:https://agc015.contest.atcoder.jp/tasks/agc015_c 题目大意: 现有一个\(N×M\)的矩阵\(S\),若\(S_{i,j}=1\),则该处为 ...
- AtCoder Grand Contest 015 E - Mr.Aoki Incubator
题目传送门:https://agc015.contest.atcoder.jp/tasks/agc015_e 题目大意: 数轴上有\(N\)个点,每个点初始时在位置\(X_i\),以\(V_i\)的速 ...
- Atcoder Grand Contest 015 F - Kenus the Ancient Greek(找性质+乱搞)
洛谷题面传送门 & Atcoder 题面传送门 一道难度 Au 的 AGC F,虽然看过题解之后感觉并不复杂,但放在现场确实挺有挑战性的. 首先第一问很简单,只要每次尽量让"辗转相除 ...
- Atcoder Grand Contest 054 题解
那天晚上由于毕业晚会与同学吃饭喝酒没打 AGC,第二天稍微补了下题,目前补到了 E,显然 AGC 的 F 对于我来说都是不可做题就没补了(bushi A 简单题,不难发现如果我们通过三次及以上的操作将 ...
- AtCoder Grand Contest 015
传送门 A - A+...+B Problem 题意:n个数最大值a,最小值b,求和的可能数量. #include<cstdio> #include<algorithm> us ...
- AtCoder Grand Contest 030题解
第一次套刷AtCoder 体验良好 传送门 Poisonous Cookies cout<<b+min(c,a+b+); Tree Burning 难度跨度有点大啊 可以证明当第一次转向之 ...
- AtCoder Grand Contest 031题解
题面 传送门 题解 比赛的之后做完\(AB\)就开始发呆了--简直菜的一笔啊-- \(A - Colorful\ Subsequence\) 如果第\(i\)个字母选,那么它前面任意一个别的字母的选择 ...
随机推荐
- LOJ3146 APIO2019路灯(cdq分治+树状数组)
每个时刻都形成若干段满足段内任意两点可达.将其视为若干正方形.则查询相当于求历史上某点被正方形包含的时刻数量.并且注意到每个时刻只有O(1)个正方形出现或消失,那么求出每个矩形的出现时间和消失时间,就 ...
- 图解javascript的this指向
图解javascript的this指向 作者: HerryLo 本文永久有效链接: https://github.com/AttemptWeb...... 以下就只有两张图,请放心食用!! #简版th ...
- CSS3 @font-face 规则
指定名为"myFirstFont"的字体,并指定在哪里可以找到它的URL: @font-face { font-family: myFirstFont; src: url('San ...
- DevExtreme学习笔记(一)treeView(搜索固定、节点展开和收缩)注意事项
var treeConfig1 = dxConfig.treeView(obj_Question.treeDataSource1); treeConfig1.selectionMode = 'sing ...
- oracle 触发器的实例(转)
触发器使用教程和命名规范 目 录 目录 触发器使用教程和命名规范 1 1,触发器简介 1 2,触发器示例 2 3,触发器语法和功能 3 4,例一:行级触发器之一 4 5,例二:行级触发器之二 4 6 ...
- select ng-change 方法中 拿不到 ng-modal 定义的变量值
在使用angularjs框架的项目中,select 的数据源有两种绑定方式,在option中使用ng-repeat循环绑定,或者在select中使用ng-option 绑定. 无论哪种绑定方式,均要使 ...
- 第三方dll签名
1.打开vs Tools下的工具命令 2.生成随机密钥对C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC>sn -k NonSignL ...
- 如何在Hybris commerce里创建一个media对象
进入backoffice的Media中心, 首先新建一个文件夹,用于存放即将创建的media对象: 取名为jerryimage: 然后创建一个新的media对象,取名jerryproductimage ...
- redis 异常 MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk
MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. 解决方 ...
- CRM-Q模糊查询
Q查询-模糊查询 示例一 q=Q() # 实例化一个Q的对象q,我们可以给它加条件 q.children.append(("name","xxx")) # 添加 ...