Atcoder 水题选做
为什么是水题选做呢?因为我只会水题啊 (
为什么是$Atcoder$呢?因为暑假学长来讲课的时候讲了三件事:不要用洛谷,不要用dev-c++,不要用单步调试。$bzoj$太难了,$Topcoder$整了好久没学会用,中国人要长期打$codeforces$那作息简直反人类,所以就选到$atcoder$啦.而且$AT$的英语感觉比较好懂,或许是因为都是亚洲人,思维比较同步?
那么哪些题目会被放到这个地方呢?$ABC$的后两题,也就是$ARC$的前两题(如果同时举办的话).至于$ARC$的后两题以及$AGC$的题,以后可能会单开一篇来写吧.似乎每当$ABC$和$ARC$一起办的时候就稍微难一点,只办$ABC$的时候题就非常水.
做了两套题后感觉有些$C$的思路还是比较妙的,最好评的是即使是$D$也不会有很高的代码难度。前段时间掉进了大数据结构&&实现麻烦的题目的大坑,现在发现自己的思维好差啊...以后要多做一点思维题.
107 C:https://arc101.contest.atcoder.jp/tasks/arc101_a
题意概述:数轴上放有$n$根蜡烛,初始时站在$0$坐标,移动的速度是一个定值,求最少用多少时间可以点亮$k$根蜡烛.
尺取法+分类讨论,如果一段区间横跨$0$坐标,那就先走离$0$近的部分,再折回来点亮另一边的,如果与$0$没有公共部分,直接一次走过去即可.
# include <cstdio>
# include <iostream>
# include <cstring>
# include <string>
# include <cmath>
# include <algorithm>
# define R register int using namespace std; const int maxn=;
int n,k,p1,p2,equ;
int cnt,a[maxn],ans; int ab (int x)
{
if(x<) return -x;
return x;
} int ask (int x,int y)
{
if(x<&&y<) return -min(x,y);
if(x>&&y>) return max(x,y);
return ab(x)+ab(y)+min(ab(x),ab(y));
} int main()
{
scanf("%d%d",&n,&k);
for (R i=;i<=n;++i)
{
scanf("%d",&a[i]);
if(a[i]<) equ=i;
}
p1=p2=equ;
if(p2<k) p2=p1=k;
cnt=;
while (cnt<k&&p1>) p1--,cnt++;
if(cnt==k) ans=ask(a[p1],a[p2]);
while (p2<n)
{
p1++;
p2++;
ans=min(ask(a[p1],a[p2]),ans);
}
printf("%d",ans);
return ;
107 C
107 D:https://arc101.contest.atcoder.jp/tasks/arc101_b
题意概述:给定一个长度为$n$的序列,对它的所有连续子区间拿出来求中位数(如果是偶数长度就取较大的那个),再将这些中位数排起来求中位数,问这个中位数是几.$n<=10^5$
中位数真是一个神奇的东西...
看到中位数就可以试一下二分答案加上离散化,这道题也不例外.首先可以算出来最终的序列一共有多少个数,所以有多少个数字应该比中位数小也就可以算出来了.二分答案之后怎么做呢?可以首先根据与$ans$的大小关系把序列离散化成$-1,1$,求一个前缀和,现在的问题是怎么求出有多少个连续序列的中位数小于$ans$,容易发现如果$s_i-s_{j-1}>0$,即$s_i>s_{j-1}$,那么$s_j-s_i$就是一个合法的区间了,使用树状数组统计即可.因为树状数组的下标不能为负数,所以统一加上一个$n+1$平移到正数.注意因为二分时可能分到不属于这个序列的数,所以二分时应当取$min$.时间复杂度$O(Nlog^2N)$
# include <cstdio>
# include <cstring>
# include <iostream>
# define R register int
# define ll long long using namespace std; const int maxn=;
int n;
int a[maxn],m,l,r,mid,ans,c[maxn],t[maxn<<]; void ins (int x) { for (R i=x;i<=*n+;i+=(i&(-i))) t[i]++; }
int ask (int x) { int ans=; for (R i=x;i;i-=(i&(-i))) ans+=t[i]; return ans; } bool check (int ans)
{
ll cnt=;
memset(t,,sizeof(t));
for (R i=;i<=n;++i)
if(a[i]<=ans) c[i]=c[i-]+;
else c[i]=c[i-]-;
ins(n+);
for (R i=;i<=n;++i)
{
cnt+=ask(c[i]+n);
ins(c[i]+n+);
}
ll b=1LL*n*(n+)/;
b/=;
return cnt>=b+;
} int main()
{
scanf("%d",&n);
for (R i=;i<=n;++i)
scanf("%d",&a[i]),m=max(m,a[i]);
l=,r=m,ans=m;
while(l<=r)
{
mid=(l+r)>>;
if(check(mid))
ans=min(ans,mid),r=mid-;
else
l=mid+;
}
printf("%d",ans);
return ;
}
D
109 C:https://abc109.contest.atcoder.jp/tasks/abc109_c
题意概述:给出$n$个城市的坐标以及起始坐标,每次可以移动$d$的距离(或正或负),求最大的$d$使得可以从起点出发经过所有点。
首先$d$必然是任意点到初始点的距离的因子,否则到不了,然后...答案就是所有点离初始点距离的最大公约数了。(这道$C$是挺水的)
# include <cstdio>
# include <iostream> using namespace std; int n,x,ans;
int a[]; int gcd (int a,int b)
{
return b?gcd(b,a%b):a;
} int main()
{
scanf("%d%d",&n,&x);
for (int i=;i<=n;++i)
{
scanf("%d",&a[i]);
a[i]-=x;
if(a[i]<) a[i]=-a[i];
}
ans=a[];
for (int i=;i<=n;++i)
ans=gcd(ans,a[i]);
printf("%d",ans);
return ;
}
109 C
109 D:https://abc109.contest.atcoder.jp/tasks/abc109_d
题意概述:给定一个$H*W$的矩阵,每个格子中有一些硬币,每次可以从一个格子向与他四联通的任意一个格子移动一个硬币(只能移动一次),使得最终的局面中有偶数个硬币的格子最多。
我感觉这个题挺好的...因为只能移动一次,可以将每个格子的硬币数量$\%2$表示奇偶性,现在问题是怎样移动使得为$0$的格子最多.四联通是一个比较麻烦的东西,因为可能导致处理完的格子再变化.但是可以发现只需要考虑向下和向右移动的情况.偶+偶=偶,奇+奇=偶,偶+奇=奇.从偶数格子里往外移动一定是不合算的,不过两个奇数格子互相传递,中间经过一个偶数格子还是可以的.从一个奇数格子往偶数格子移动一定不会使解更劣:如果后来又将这个多余的硬币移到了奇数格子就可以使解加一,即使不可以,也不过是调换了这两个格子的奇偶性.这是这道题的解法就基本成型了:从上到下遍历棋盘,如果遇到奇数就往右边移动一个,如果已经是最后一列就考虑往下移动,这样构造出来的答案一定是最优的。
# include <cstdio>
# include <iostream> using namespace std; int h,w,f=,j,x,lasx,lasy;
int g[][];
int H,a[],b[],c[],d[]; int main()
{
scanf("%d%d",&h,&w);
for (int i=;i<=h;++i)
for (int j=;j<=w;++j)
scanf("%d",&g[i][j]),g[i][j]%=;
for (int i=;i<=h;++i)
{
if(i%) j=; else j=w;
while (<=j&&j<=w)
{
if(x)
{
a[++H]=lasx,b[H]=lasy,c[H]=i,d[H]=j;
if(g[i][j]) x=;
}
else if(g[i][j]) x=;
lasx=i;
lasy=j;
j+=f;
}
f=-f;
}
printf("%d\n",H);
for (int i=;i<=H;++i)
printf("%d %d %d %d\n",a[i],b[i],c[i],d[i]);
return ;
}
109 D
110 C:https://abc110.contest.atcoder.jp/tasks/abc110_c
题意概述:给出两个字符串,要求构造一个字符的映射关系,使得$S$=$T$.
这题的难度一半在于读题,题面里那个置换非常有迷惑性,题目说的是可以任意将两种字母进行整体交换,其实就是要找到一个映射关系.
似乎就是$NOIP$潜伏者那道题?总之就是开两个桶记录两个集合之间的对应关系,如果出现矛盾就...有矛盾啊.
# include <cstdio>
# include <iostream>
# include <queue>
# include <algorithm>
# include <cstring>
# include <string>
# define R register int
# define ll long long using namespace std; const int maxn=;
char s[maxn],t[maxn];
int a[],b[],len,ans=; int main()
{
scanf("%s",s+);
scanf("%s",t+);
len=strlen(s+);
for (R i=;i<=len;++i)
{
if(a[ s[i]-'a'+ ]==) a[ s[i]-'a'+ ]=t[i]-'a'+;
else if(a[ s[i]-'a'+ ]!=t[i]-'a'+) ans=;
if(b[ t[i]-'a'+ ]==) b[ t[i]-'a'+ ]=s[i]-'a'+;
else if(b[ t[i]-'a'+ ]!=s[i]-'a'+) ans=;
}
if(ans) printf("No");
else printf("Yes");
return ;
}
110 C
111 D:https://abc110.contest.atcoder.jp/tasks/abc110_d
题意概述:给出$n,m$,问满足下面式子的数列有多少个.$n<=10^5,m<=10^9$
$10^9$基本上就钦定是根号级别的算法了,线性是不可能的,$log$还不如开到$long$ $long$,大胆猜测首先要分解$m$。
题目就被转化成了,将$m$的质因数排成一排,可以任意合并,求个数小于等于$n$的方案数.虽然题目说的是严格等于$n$,然而不够时添$1$即可.
然后就会发现这个转化毫无意义~,而且还提高了编写的难度.
可以用另一种思路来做这个题,考虑设置$n$个盒子,每个盒子里存一个数,一开始都是$1$,每次往盒子里面放数就相当于把这个数乘进去.此时我们有了一个非常有利于解题的模型,对于每种质因数单独考虑,利用乘法原理统计答案.对于每种质因数应当怎么做呢?等价于将$n$个无差别物体放进$m$个有差别盒子中,允许有空盒子,设置$m$个虚点后插板法即可.
# include <cstdio>
# include <iostream>
# include <queue>
# include <cstring>
# include <string>
# define mod
# define R register int
# define ll long long using namespace std; const int maxn=;
int n,m,fac=,h;
int p[maxn],c[maxn];
ll f[maxn],inv[maxn];
ll ans=; ll qui (ll a,ll b)
{
ll s=;
while (b)
{
if(b&1LL) s=s*a%mod;
a=a*a%mod;
b=b>>1LL;
}
return s%mod;
} ll C (int a,int b)
{
return f[b]*qui(f[a],mod-)%mod*qui(f[b-a],mod-)%mod;
} int main()
{
scanf("%d%d",&n,&m);
f[]=;
for (R i=;i<=n+;++i)
f[i]=1LL*i*f[i-]%mod;
for (R i=;1LL*i*i<=m;++i)
{
if(m%i==) p[++h]=i;
while (m%i==) c[h]++,m/=i;
}
if(m!=) p[++h]=m,c[h]=;
for (R i=;i<=h;++i)
ans=(ans*C(n-,n+c[i]-))%mod;
printf("%lld",ans%mod);
return ;
}
110 D
111 C:https://abc111.contest.atcoder.jp/tasks/arc103_a
2018.10.6:一个月没做发现只缺了两场,开心~
题意概述:给定一个长度为$n$的序列(保证$n$是偶数),可以随意改动序列中的数字,要求改成ABABABAB的形式,($A!=B$),求最少需要改动的次数.
自以为是道很水的题,然而$WA$了两次,要注意细节啊...其实思路挺简单的,对于奇数部分和偶数部分分开考虑,找到出现次数最多的那个数字,之后将不是这个数字的数字都变成这个就好了...吗?注意$A!=B$,这时我的做法就处理不了了.其实加上这个限制也没有麻烦多少,再记录两个次大值,如果出现冲突就找一个次大值换上,这道题就做完了.最近见了不少记录次大值的题目,过两天凑上几个一起写一下.
# include <cstdio>
# define R register int using namespace std; const int maxn=;
int n,M,ans,cnt,a[maxn],v[maxn],b1,b2,mb1,mb2,mc1,mc2,c1,c2; inline int min (int a,int b) { return b>=a?a:b; }
inline int max (int a,int b) { return b>=a?b:a; } int main()
{
scanf("%d",&n);
for (R i=;i<=n;++i)
scanf("%d",&a[i]),M=max(M,a[i]);
for (R i=;i<=n;i+=)
v[ a[i] ]++;
for (R i=;i<=M;++i)
if(v[i]>=mb1)
b2=b1,mb2=mb1,mb1=v[i],b1=i;
else
if(v[i]>mb2) mb2=v[i],b2=i;
for (R i=;i<=n;i+=)
v[ a[i] ]--;
for (R i=;i<=n;i+=)
v[ a[i] ]++;
for (R i=;i<=M;++i)
if(v[i]>=mc1)
c2=c1,mc2=mc1,mc1=v[i],c1=i;
else
if(v[i]>mc2) mc2=v[i],c2=i;
if(b1!=c1)
ans=n-mb1-mc1;
else
ans=min(n-mb1-mc2,n-mb2-mc1);
printf("%d",ans);
return ;
}
111 C
111 D:https://abc111.contest.atcoder.jp/tasks/arc103_b
题意概述:构造题。给定平面上的$n$个点,要求构造一条包含多个部分的机械臂,每个部分之间有一个关节,起点在$(0,0)$位置,每个关节处可以选择四种方向,要求终点处正好在给定点上。需要构造的部分:部分的数量,每段的长度,对于每一个点应采取的方向序列。无解输出$-1$
一看到这道题以为自己又可以开心的水一道水题了,结果是被水题给水了...后来发现这次是和$ARC$一起办的,所以难一些.首先我觉得每个部分如果都是$1$肯定是最好的,非常灵活,部分数量就是所有点中距离原点的曼哈顿距离最大的那个距离.如果有两个点的曼哈顿距离的奇偶性不同,那么这两个点就不可能被同时到达,为无解.这个做法听起来非常美好,$OLE$之后才发现题目上写了一行$m<=40$,也就是不能超过四十个部分...以后再也不用全屏翻译的功能了,把这句话都给翻译成乱码了.看了题解发现是一个二进制构造,其实这种拼凑数字的题好多都是二进制,但是这个题包装的比较复杂,就没看出来.判断无解那里我写的是正确的,的确要求奇偶性相同,构造方法如下:从$2^{31}$开始,把每个$2$的幂次方都放上,如果目标距离是偶数就再加一条长度为一的边.摆放的时候采取一种修修补补的策略,目前哪个方向离目标差的比较多就把下一条机械臂指向那个方向即可.至于证明,有一个博客写的非常好:https://blog.csdn.net/zxyoi_dreamer/article/details/82905515
# include <cstdio>
# include <iostream>
# include <cstring>
# include <cmath>
# include <algorithm>
# include <string>
# define ll long long
# define R register int using namespace std; const int maxn=;
int n,m,f=-;
ll x[maxn],y[maxn];
ll d[],len; inline ll ab (ll x) { if(x<) return -x; return x; } inline void solve (ll x,ll y)
{
for (R i=;i<=m-((f&)^);++i)
{
if(ab(x)>ab(y))
{
if(x>) putchar('R'),x-=d[i];
else putchar('L'),x+=d[i];
}
else
{
if(y>) putchar('U'),y-=d[i];
else putchar('D'),y+=d[i];
}
}
if(f%==) putchar('L');
putchar('\n');
} int main()
{
scanf("%d",&n);
for (R i=;i<=n;++i)
{
scanf("%lld%lld",&x[i],&y[i]);
len=ab(x[i])+ab(y[i]);
if(f==-) f=len%;
if(f%!=len%)
{
printf("-1");
return ;
}
}
for (R i=;i>=;--i) d[++m]=(1LL<<i);
if(f%==) d[++m]=;
printf("%d\n",m);
for (R i=;i<=m;++i)
{
printf("%lld",d[i]);
if(i==m) printf("\n");
else printf(" ");
}
for (R i=;i<=n;++i)
solve(x[i]+((f&)^),y[i]);
return ;
}
111 D
112 C:https://abc112.contest.atcoder.jp/tasks/abc112_c
本来今天是要做生成树的题目的,但是重启电脑后发现用来列任务清单的软件没了...所以又来做$AT$了.
这场$AT$好像挺水的,竟然有$576$个$AK$选手,$\%\%\%$
题意概述:有一个金字塔,中心点位于$(C_x,C_y)$每个点的高度有这样一个计算公式:$max(H-|x-C_x|-|y-C_y|,0)$,给出$n$个点的坐标及其高度,试求出金字塔的中心点。
看到这道题觉得简直太妙啦,是不是要用到绝对值化简的性质呢?是不是可以二分套二分呢?这时我看到了数据范围:保证中心点的横纵坐标都是整数,且位于区间$[0,100]$,给出点的数量不会超过$100$...突然想起金牌爷之前跟我说的"做思维题做多了,每见到一个题就有五六种奇思妙想,其实暴力就行"...
注意...边界...有一个小细节:如果某一次的高度为$0$,其实也就是给金字塔的高度设定了一个上限,这里一定要记住保存一下这个边界,等到输出前再看一看高度是否超出了这个边界即可$AC$
# include <cstdio>
# include <iostream>
# define R register int using namespace std; const int maxn=;
int n,w;
int x[maxn],y[maxn],h[maxn]; inline int ab (int a) { if(a<) return -a; return a; } inline bool check (int cx,int cy)
{
int hh,X=;
w=-;
for (R i=;i<=n;++i)
{
if(h[i]==)
{
if(w==-)
{
X=min(X,ab(x[i]-cx)+ab(y[i]-cy));
continue;
}
if(w-ab(x[i]-cx)-ab(y[i]-cy)>) return false;
continue;
}
hh=ab(x[i]-cx)+ab(y[i]-cy)+h[i];
if(w==-) w=hh;
if(hh!=w) return false;
}
if(w==-) return false;
if(w>X) return false;
return true;
} int main()
{
scanf("%d",&n);
for (R i=;i<=n;++i)
scanf("%d%d%d",&x[i],&y[i],&h[i]);
for (R i=;i<=;++i)
for (R j=;j<=;++j)
{
if(check(i,j))
{
printf("%d %d %d",i,j,w);
return ;
}
}
return ;
}
112 C
112 D:https://abc112.contest.atcoder.jp/tasks/abc112_d
题意概述:把一个数分成$n$份,使这$n$个数的最大公约数最大,输出.
$AT$还真喜欢出构造题.然而我最不会的就是构造题了.
这道题几乎可以说是我自己做出来的第一道构造啦,留念$2018-10-08$ $21:38:31$
首先我们可以对这个式子进行一番变形:$k*a_1+k*a_2+……+k*a_n=M$,再提取一下公因数:
所以答案一定是$m$的一个因子,但是不是每一个因子都能成为答案,玩一下第一个样例就能发现.为什么呢?因为$m$除以$k$之后可能根本组不出$n$个数来...所以要判断一下除出来的数字是否大于$n$.这里不能再枚举质因数了,要枚举约数,两个注意事项:
·$1$和$n$都是$n$的约数;
·每枚举一个因数就要枚举$m$除以它的那个因数,可以将复杂度降到$\sqrt{M}$
# include <cstdio>
# include <iostream>
using namespace std; int n,m,ans; inline void check (int x) { if(m/x>=n) ans=max(ans,x); } int main()
{
scanf("%d%d",&n,&m);
for (int i=;i*i<=m;++i)
{
if(m%i) continue;
check(i);
check(m/i);
}
printf("%d",ans);
return ;
}
D
Atcoder 水题选做的更多相关文章
- 贪心/构造/DP 杂题选做Ⅲ
颓!颓!颓!(bushi 前传: 贪心/构造/DP 杂题选做 贪心/构造/DP 杂题选做Ⅱ 51. CF758E Broken Tree 讲个笑话,这道题是 11.3 模拟赛的 T2,模拟赛里那道题的 ...
- 贪心/构造/DP 杂题选做Ⅱ
由于换了台电脑,而我的贪心 & 构造能力依然很拉跨,所以决定再开一个坑( 前传: 贪心/构造/DP 杂题选做 u1s1 我预感还有Ⅲ(欸,这不是我在多项式Ⅱ中说过的原话吗) 24. P5912 ...
- 贪心/构造/DP 杂题选做
本博客将会收录一些贪心/构造的我认为较有价值的题目,这样可以有效的避免日后碰到 P7115 或者 P7915 这样的题就束手无策进而垫底的情况/dk 某些题目虽然跟贪心关系不大,但是在 CF 上有个 ...
- [SDOI2016]部分题选做
听说SDOI蛮简单的,但是SD蛮强的.. 之所以是选做,是因为自己某些知识水平还不到位,而且目前联赛在即,不好花时间去学sa啊之类的.. bzoj4513储能表&bzoj4514数字配对 已写 ...
- 历年NOIP水题泛做
快noip了就乱做一下历年的noip题目咯.. noip2014 飞扬的小鸟 其实这道题并不是很难,但是就有点难搞 听说男神错了一个小时.. 就是$f_{i,j}$表示在第$i$个位置高度为$j$的时 ...
- 【SPOJ GSS】数据结构题选做
SPOJ GSS1 题意:给一个序列以及一些询问,每个是问\([l,r]\)中最大连续子序列和是多少. 思路:这个问题是以下问题的基础. 我们考虑用线段树来解决这个问题. 首先我们来想想如果要求出最大 ...
- [NOIP2017(TG/PJ)] 真题选做
[NOIPTG2017] 小凯的疑惑 题意 小凯有两种面值的金币,每种金币有无数个,求在无法准确支付的物品中,最贵的价值是多少金币. 分析 设两种金币面值分别为 $a$ 和 $b \; (a<b ...
- 『CUDA C编程权威指南』第二章编程题选做
第一题 设置线程块中线程数为1024效果优于设置为1023,且提升明显,不过原因未知,以后章节看看能不能回答. 第二题 参考文件sumArraysOnGPUtimer.cu,设置block=256,新 ...
- 期望dp好题选做
前言: 最近连考两场期望dp的题目,sir说十分板子的题目我竟然一点也不会,而且讲过以后也觉得很不可改.于是开个坑. 1.晚测10 T2 大佬(kat) 明明有\(O(mlog)\)的写法,但是\(m ...
随机推荐
- CSS学习笔记04 CSS文字排版常用属性
字体样式属性 font-size:字号大小 font-size属性用于设置字号,该属性的值可以使用相对长度单位,也可以使用绝对长度单位.其中,相对长度单位比较常用,推荐使用像素单位px,绝对长度单位使 ...
- 【Java基础】7、Java同步机制之Monitor监视器与syncrhoized实现原理
一:Monitor Monitor是一个同步工具,相当于操作系统中的互斥量(mutex),即值为1的信号量. 它内置与每一个Object对象中,相当于一个许可证.拿到许可证即可以进行操作,没有拿到则需 ...
- jsonp 实现跨域
为什么会出现跨域问题 跨域的安全限制都是对浏览器端来说的,服务器端是不存在跨域安全限制的. 浏览器的同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互. 如果协议,端口和主机对于两个页面 ...
- css选取table元素的第一列
table tr td:first-child
- js多线程(worker)
浏览器端js是单线程执行,所以当js执行高负载运算时,UI渲染就会阻塞,页面就会出现卡顿,用户体验就不是很好 js为此也提供了异步操作,例如: 定时器(setTimeout 和 setInterval ...
- java中System.currentTimeMillis()
System.curentTimeMillis();会产生一个当前的毫秒. 1.计算某个方法的耗时 long curTime = System.currentTimeMillis(); resourc ...
- 【mpvue】使用Mpvue撸一个简单的小程序
一.快速创建一个mpvue项目 全局安装 vue-cli (如果有就不需要装了) 创建一个基于mpvue-quickstart模板的新项目,记得选择安装vuex vue init mpvue/ ...
- JSP内置对象——session对象
举个购物流程的例子: 这整个购物过程,它是属于一次回话.那么这个session是保存在服务器内存当中,并且它保存着不同用户对应的session,一个用户对应一个session.看下面这幅图: 从图中可 ...
- SQLServer 2005客户端远程连接sql2008 数据库服务器
SQL2005客户端远程连接sql2008 数据库服务器 by:授客 QQ:1033553122 准备工作: 客户端所在pc机配置: 配置数据源 控制面板-管理工具-ODBC数据源-系统DSN-添加- ...
- RBAC用户权限管理数据库设计【转载】
本文转载自:https://www.kancloud.cn/martist/ma_zhao_liu/374123 简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成“用户-角色-权 ...