AGC019
质量果然挺高的。
A
贪心。
ll Q,H,S,D,N;
int main()
{
cin>>Q>>H>>S>>D>>N;
H=min(H,Q+Q);
S=min(S,H+H);
D=min(D,S+S);
ll ans=N/2*D+(N&1)*S;
cout<<ans<<"\n";
}
B
认真目测样例可以发现答案为不相等的字符对数+1。
char str[SZ]; int n;
int app[SZ];
int main()
{
scanf("%s",str+1);
n=strlen(str+1);
for(int i=1;i<=n;++i)
++app[str[i]];
ll tot=n*(ll)(n-1)/2;
for(int i='a';i<='z';++i)
tot-=(app[i]-1)*ll(app[i])/2;
cout<<tot+1<<"\n";
}
C
首先答案大体上就是曼哈顿距离*100,为了几个喷泉绕路显然不优。
每一个可以使答案变小20-5pi,每个会使答案变大10pi-20。
为了让尽量多,我们会经过尽量多的喷泉,这个可以直接按行排序之后把列LIS。
什么时候会有呢?只有正好每行或者每列都怼了一个喷泉的时候。判一下就好了。
#define y1 yyy1
#define y2 yyy2
int x1,y1,x2,y2,n;
pii ps[SZ];
ld pi=acos(-1);
int bs[SZ];
void upd(int x,int y)
{
for(;x<=n;x+=x&-x) bs[x]=max(bs[x],y);
}
int qmax(int x)
{
int ans=-1e9;
for(;x>=1;x-=x&-x) ans=max(ans,bs[x]);
return ans;
}
#define yn yyn
int ys[SZ],yn=0;
int lis[SZ];
int main()
{
memset(bs,-127/3,sizeof bs);
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&n);
for(int i=1;i<=n;++i)
scanf("%d%d",&ps[i].fi,&ps[i].se);
if(x1>x2)
{
x1*=-1; x2*=-1;
for(int i=1;i<=n;++i)
ps[i].fi*=-1;
}
if(y1>y2)
{
y1*=-1; y2*=-1;
for(int i=1;i<=n;++i)
ps[i].se*=-1;
}
ps[++n]=pii(x1,y1);
ps[++n]=pii(x2,y2);
sort(ps+1,ps+1+n);
for(int i=1;i<=n;++i)
ys[++yn]=ps[i].se;
sort(ys+1,ys+1+yn);
int yy1=lower_bound(ys+1,ys+1+yn,y1)-ys;
int yy2=lower_bound(ys+1,ys+1+yn,y2)-ys;
for(int i=1;i<=n;++i)
ps[i].se=lower_bound(ys+1,ys+1+yn,ps[i].se)-ys;
int rr=0;
for(int i=1;i<=n;++i)
{
lis[i]=qmax(ps[i].se)+1;
if(ps[i]==pii(x1,yy1)) lis[i]=0;
else if(ps[i]==pii(x2,yy2)) rr=lis[i]-1;
upd(ps[i].se,lis[i]);
}
ld ans=(x2-x1)+(y2-y1);
ans*=100.0;
ans+=(pi-4)*5*rr;
if(rr==min(x2-x1+1,y2-y1+1)&&rr)
ans+=pi*5;
printf("%.20lf\n",ans);
}
D
为了方便描述,我们记一个计数器t,往右+1,往左-1。那么当前a[i]对着的就是b[i+t](模|A|意义下)。
假设我们枚举最后相等的时候的t=s,那么a[i]对着b[i+s],我们就知道了哪些位需要flip一下。
考虑A在转的时候设计数器最小值为minn,最大值为maxn(minn<=0<=maxn)。要翻转A的某一位,可以往左转到第一个B为1的位置,也可以往右转到第一个B为1的位置,即有一个条件minn<=某个值 或者 maxn>=某个值。
要取到某个minn和maxn、最后到达s,需要的最小翻的次数是多少呢?可以发现恰好是2(maxn-minn)-|s|。这个公式可以这么理解:如果s=0,那么显然要2(maxn-minn),先移到maxn,再移到minn,再移回来或者先到minn再到maxn再回来。如果s>0,那么先到minn,再到maxn,然后只要移回到s,所以就是2(maxn-minn)-s。
假设s>=0,那么需要次数就是2(maxn-minn)-s,并且maxn>=s,minn<=0。设x=-minn,y=maxn-s,那么我们就是要最小化2(y+s+x)-s=2(x+y)+s,即最小化x+y,原来的条件就是x>=某个数 or y>=某个数。扫一下就好了。(从大到小枚举x,对不满足x的y需求取max)
如果s<0那就把A和B全翻过来。
char A[SZ],B[SZ]; int n,ans;
int mi[SZ],ma[SZ],mx[SZ];
void work()
{
for(int i=0;i<n;++i)
{
mi[i]=ma[i]=0;
while(B[(i+ma[i])%n]!='1') ++ma[i];
while(B[(i+mi[i]+n)%n]!='1') --mi[i];
}
for(int s=0;s<n;++s)
{
for(int r=0;r<n;++r) mx[r]=0;
int dif=0;
for(int r=0;r<n;++r) if(A[r]!=B[(r+s)%n])
mx[-mi[r]]=max(mx[-mi[r]],ma[r]-s),++dif;
int ly=0,ca=1e9;
for(int r=n-1;r>=0;--r)
ca=min(ca,ly+r), ly=max(ly,mx[r]);
ans=min(ans,2*ca+s+dif);
}
}
int main()
{
scanf("%s%s",A,B);
n=strlen(A); ans=1e9;
bool ha=0,hb=0;
for(int i=0;i<n;++i)
if(A[i]=='1')ha=1;
for(int i=0;i<n;++i)
if(B[i]=='1')hb=1;
if(!hb)
{
if(ha) puts("-1");
else puts("0");
return 0;
}
work(); reverse(A,A+n);
reverse(B,B+n); work();
printf("%d\n",ans);
}
E
这里讲一下 http://codeforces.com/blog/entry/54027?#comment-381549 这个做法。
考虑swap有几种:
A 10 10 11 11
B 01 11 11 01
其中
11
01
交换完之后第一列的10就固定了,直接就GG了。
首先我们可以注意到01和10的列数是一样的(否则A和B里1的个数就不同了)。
我们先考虑11 11这种情况,贡献A的一方只能是11,因为如果是01换过来一个1,那么A已经换过了,贡献B的一方可以是换过来一个1的01(而且01合法的只能是换过来一个1)(注意这里贡献A和B的可以是同一个)。
因为11 11换了也是白换,所以我们可以先把这部分的方案数计算一下。
假设有x个列为01,y个列为11,设有y-i个11 11这种情况,那么贡献A的可以是y个中任一,贡献B的可以是x+y中任一,所以只要把另外两种情况的方案数乘上就好。
接下来我们只有
10 和 10 这两种情况了。
01 11
此时,设g[x][i]为有x个列为01,x个列为10,i个列为11的方案数,那么g[x][i]=x^2g[x-1][i](10和01匹配)+xig[x][i-1](11和01匹配)
通过换元这个式子还可以进一步化简,不是重点这里就不说了,可以参看上面那个链接。
char A[SZ],B[SZ];
int n;
ll f[10009];
#define MOD 998244353
ll fac[SZ],rfac[SZ];
ll qp(ll a,ll b)
{
ll x=1;
while(b)
{
if(b&1) x=x*a%MOD;
a=a*a%MOD; b>>=1;
}
return x;
}
int main()
{
fac[0]=1;
for(int i=1;i<SZ;++i)
fac[i]=fac[i-1]*i%MOD;
rfac[SZ-1]=qp(fac[SZ-1],MOD-2);
for(int i=SZ-1;i>=1;--i)
rfac[i-1]=rfac[i]*i%MOD;
scanf("%s%s",A+1,B+1); n=strlen(A+1);
int x=0,y=0;
for(int i=1;i<=n;++i) if(A[i]=='1')
(B[i]=='0')?(++x):(++y);
f[0]=1;
for(int i=1;i<=x;++i)
for(int j=1;j<=y;++j)
f[j]=(f[j]+i*f[j-1])%MOD;
ll ans=0;
for(int j=0;j<=y;++j)
ans=(ans+f[j]*rfac[x+j])%MOD;
ans=ans*fac[x]%MOD*fac[x]%MOD
*fac[y]%MOD*fac[x+y]%MOD;
ans=(ans%MOD+MOD)%MOD;
printf("%d\n",int(ans));
}
多项式做法可以参见 http://blog.csdn.net/wxh010910/article/details/77622473
F
因为每次回答后都告诉了你正误,所以最优策略一定是答剩的比较多的一个,答对概率就是 剩的多的个数 / 总个数。
考虑把回答的过程画成图中这样,每个点上标上之前说的 剩的多的个数/总个数,那么问的就是这个网格图中往右往下走从S到T的期望路径长度。
考虑把分子不一样的格线标成实线,那么图一定形如这样
主要的思路是从T开始一条一条对角线往上枚举。一条路径显然恰过每条对角线的一个点。
考虑一条路径在当前这条对角线的交点的分子,如果我们知道了每个分子的和,那么ans+=分子/公分母/路径数 即可。
如下图考虑一条分子为5433的对角线,上一条对角线分子为4323。
考虑一条路径经过上一条对角线之后经过这一条对角线,分子只能+1或者不变,如果经过实线的话就会+1,否则不变。
那么现在我们的任务就变成了统计经过这些实线的路径条数。
如上图,我们先考虑横着的实线,计数线不太好,我们考虑把格子往左压扁一格:
显然原来经过实线对应现在经过绿点。
这个计数仍然不好计,考虑还是利用递推,假设我们知道了上一条对角线经过这些点的方案数如何推出下一条的?
有两种基本情况:
假设我们知道了经过橙点的方案数。
这种情况下考虑经过紫点的路径一定也经过橙点,而经过橙点的路径,不经过紫点的只有经过最右边那个橙点,并且没经过最右边的紫点的路径,方案数即从(S到这个橙点路径数-S到最右边紫点路径数)*这个橙点到T的路径数。
这种情况类似,经过紫点而不经过橙点的路径数只有 S到最右边紫点路径数*(最右边紫点到T路径数-最右边橙点到T路径数)。
需要注意的是实际上是哪种情况并不是由点数决定的,而是由最右边的紫点和橙点的位置关系决定的。
如何方便地求出某两条对角线间最右边的一段实线呢?如图(瞎画的,不要在意细节):
把对角线和灰线求交点,上/下取整即为最右边的实线位置。
#define SZ 1234567
int n,m;
const int MOD=998244353;
ll fac[SZ],rfac[SZ];
ll qp(ll a,ll b)
{
ll x=1;
while(b)
{
if(b&1) x=x*a%MOD;
a=a*a%MOD; b>>=1;
}
return x;
}
inline ll rt(int a,int b)
{
return fac[a+b]*rfac[a]%MOD*rfac[b]%MOD;
}
int main()
{
fac[0]=1;
for(int i=1;i<SZ;++i) fac[i]=fac[i-1]*i%MOD;
rfac[SZ-1]=qp(fac[SZ-1],MOD-2);
for(int i=SZ-1;i>=1;--i)
rfac[i-1]=rfac[i]*i%MOD;
cin>>n>>m;
if(n>m) swap(n,m);
//灰线为y=x+m-n
int px1,py1,px2,py2; ll cv1,cv2,cv=0,ans=0;
//考虑对角线x+y=g和x+y=g+1的关系
for(int g=m+n-1;g>=0;--g)
{
{
int r=max(g+n-m+1,0),y,u=min(g,n);
if(r&1) y=(r+1)/2;
else y=r/2;
int a=y,b=g-y;
if(y==u) cv1=rt(y,g-y)*rt(n-y,m-1-(g-y))%MOD;
else if(px1==a)
cv1-=(rt(px1,py1)-rt(a,b))*rt(n-px1,m-1-py1)%MOD;
else
cv1+=rt(a,b)*(rt(n-a,m-1-b)-rt(n-px1,m-1-py1))%MOD;
px1=a; py1=b; cv1%=MOD;
}
{
int r=g+n-m+1,y,d=max(g-m,0);
if(r&1) y=(r-1)/2;
else y=r/2; --y;
if(d>y) cv2=0;
else
{
int a=y,b=g-y;
if(y==d) cv2=rt(y,g-y)*rt(n-1-y,m-(g-y))%MOD;
else if(px2!=a)
cv2-=(rt(px2,py2)-rt(a,b))*rt(n-1-px2,m-py2)%MOD;
else
cv2+=rt(a,b)*(rt(n-1-a,m-b)-rt(n-1-px2,m-py2))%MOD;
px2=a; py2=b; cv2%=MOD;
}
}
cv+=cv1+cv2; cv%=MOD;
ans+=cv*qp(m+n-g,MOD-2)%MOD;
}
ans=ans%MOD*qp(rt(n,m),MOD-2)%MOD;
ans=(ans%MOD+MOD)%MOD;
printf("%d\n",int(ans));
}
UPD:wxh吊打tourist http://blog.csdn.net/wxh010910/article/details/77752687
考虑答案变得不那么套路的时候,就是经过灰线的时候,直接算就好了
AGC019的更多相关文章
- 【AtCoder】AGC019
A - Ice Tea Store 算一下每种零售最少的钱就行,然后优先买2,零头买1 #include <bits/stdc++.h> #define fi first #define ...
- 10.23 正睿停课训练 Day7
目录 2018.10.23 正睿停课训练 Day7 A 矩形(组合) B 翻转(思路) C 求和(思路 三元环计数) 考试代码 B1 B2 C 2018.10.23 正睿停课训练 Day7 期望得分: ...
- B - Reverse and Compare 小小思维题
http://agc019.contest.atcoder.jp/tasks/agc019_b 一开始的做法是, 用总数减去回文子串数目,因为回文子串怎么翻转都不影响答案. 然后,如果翻转afucka ...
- AtCoder整理(持续更新中……)
做了那么久的atcoder觉得自己的题解发的很乱 给有想和我一起交流atcoder题目(或者指出我做法的很菜)(或者指责我为什么整场比赛只会抄题解)的同学一个索引的机会??? 于是写了个爬虫爬了下 A ...
- 【做题记录】AtCoder AGC做题记录
做一下AtCoder的AGC锻炼一下思维吧 目前已做题数: 75 总共题数: 239 每一场比赛后面的字母是做完的题,括号里是写完题解的题 AGC001: ABCDEF (DEF) AGC002: A ...
- AtCoder AGC019E Shuffle and Swap (DP、FFT、多项式求逆、多项式快速幂)
题目链接 https://atcoder.jp/contests/agc019/tasks/agc019_e 题解 tourist的神仙E题啊做不来做不来--这题我好像想歪了啊= =-- 首先我们可以 ...
随机推荐
- Tomcat源码学习(3)—— Digester介绍
Digester方法详解: 通读Digester之前先分析下他的结构: 1.1该类继承了方法DefaultHandler2,DefaultHandler2继承了DefaultHandler是和sax解 ...
- zookeeper_节点数据版本号问题
转自:Simba_cheng 更新节点数据的方法: 同步方法:Stat setData(final String path, byte data[], int version) 异步方法:void s ...
- jQuery的基本使用
一.jQuery简介 jQuery是一个快速.简洁的JavaScript框架,它封装了JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作.事件处理.动 ...
- 前端_html
目录 HTML介绍 标签说明 常用标签 <!DOCTYPE>标签 <head>内常用标签 <body>内常用标签 特殊字符 其他:各种各样的标签 HTML的规范 H ...
- 苹果针对on sale 的APP发的问题邮件
2017年3月8日 上午8:07 发件人 Apple Dear Developer, Your app, extension, and/or linked framework appears to c ...
- “秒杀”问题的数据库和SQL设计【转载】
“秒杀”问题的数据库和SQL设计 APRIL 21ST, 2015 问题的来源 完全不考虑一致性的方案 表结构 方案 存在的问题 保证单用户不会重复购买 解决超卖问题 方案 优化 提高性能了 鱼与熊掌 ...
- 【探路者】Postmortem会议(“事后诸葛亮”会议)
[探路者]Postmortem会议(“事后诸葛亮”会议) 整理:米赫 设想和目标 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的贪吃蛇游戏主要将完成一个 ...
- 用java构造一个带层次的文件目录遍历器
import java.util.List; import java.io.File; import java.util.ArrayList; public class IteratorUtil { ...
- Servet3.0于Servlet2.5比较
Servet3.0于Servlet2.5比较恢复 首先是利用注解代替配置文件 Servlet2.5利用配置文件对Servlet进行配置 例如这样 <servlet> <servlet ...
- Code128
条形码 条形码(barcode)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符.常见的条形码是由反射率相差很大的黑条(简称条)和白条(简称空)排成的平行线图案.条形 ...