第一次套刷AtCoder

体验良好

传送门


Poisonous Cookies

cout<<b+min(c,a+b+);

Tree Burning

难度跨度有点大啊

可以证明当第一次转向之后,接下来每次的方向都和前一次相反

因为转向后再往相同方向走一定不如初始就往该方向走然后转两次向

枚举初始往哪个方向走以及走几步,前缀和优化即可

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans;ll ret;
int a[];
ll hz[],qz[],qzh[];
void calc(){
for(rt i=n-;i>=;i--)hz[i]=hz[i+]+2ll*(n-i)*a[i];
qz[]=qzh[]=a[];
for(rt i=;i<=n;i++)qz[i]=qz[i-]+(2ll*i-)*a[i],qzh[i]=qzh[i-]+a[i];
ll ans=;
for(rt i=;i<=n;i++){
ans+=a[i];int md=i+n>>;
ret=max(ret,ans-hz[md+]-(qz[md]-qz[i]-(qzh[md]-qzh[i])*2ll*i)+qzh[n]*(n-i-));
}
}
int main(){
int L=read();n=read();a[++n]=L;
for(rt i=;i<n;i++)a[i]=read();
for(rt i=n;i>=;i--)a[i]-=a[i-];
calc();reverse(a+,a+n+);calc();
cout<<ret;
return ;
}

Coloring Torus

清真构造题

若$ k\leq n$显然可以构一个$ k*k$的正方形,第$ i$行全填$ i$即可

当$ n < k \leq 2n$时,尝试从斜向入手

发现每个斜行可以交错填写数字,这样能填写的数字就能达到$ 2n$级别了

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define p 1000000007
#define inv2 500000004
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans[][];
int main(){
k=read();
if(k<=){
writeln(k);
for(rt i=;i<=k;i++)for(rt j=;j<=k;j++)cout<<i<<" \n"[j==k];
return ;
}
writeln(n=);
for(rt i=;i<=n;i++){
ans[][i]=i;
for(rt x=n,y=i%n+;x!=;x--,y=y%n+)ans[x][y]=i;
}
for(rt i=n+;i<=k;i++){
if(i+i&)ans[][i]=i;
for(rt x=n,y=i%n+;x!=;x--,y=y%n+)if(i+y&)ans[x][y]=i;
}
for(rt i=;i<=n;i++)for(rt j=;j<=n;j++)cout<<ans[i][j]<<" \n"[j==n];
return ;
}

Inversion Sum

比B和C都清真多了...

设$ f[i][j][k]$表示经过$ i$次操作,$ a_j>a_k$的方案数

容易发现每次操作只对$ O(n)$级别的状态进行了非乘2的修改,其他都只是继承状态然后$ *2$

不妨把状态改成经过$ i$次操作,每次操作有$ 50\%$概率交换两个数,求逆序对的期望

滚动数组之后可以$ O(n^2)$解决转移,最后乘上$ 2^q$即可

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define p 1000000007
#define inv2 500000004
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans;
int f[][],g[][],a[];
int main(){
n=read();m=read();
for(rt i=;i<=n;i++)a[i]=read();
for(rt i=;i<=n;i++)
for(rt j=;j<=n;j++)if(a[i]>a[j])f[i][j]=;
for(rt i=;i<=m;i++){
x=read();y=read();
for(rt j=;j<=n;j++)g[x][j]=f[x][j],g[j][x]=f[j][x],g[y][j]=f[y][j],g[j][y]=f[j][y];
f[x][y]=f[y][x]=1ll*(g[x][y]+g[y][x])*inv2%p;
for(rt j=;j<=n;j++){
const int v1=1ll*(g[x][j]+g[y][j])*inv2%p,v2=1ll*(g[j][x]+g[j][y])*inv2%p;
if(j!=y&&j!=x)f[x][j]=v1,f[j][x]=v2;
if(j!=x&&j!=y)f[y][j]=v1,f[j][y]=v2;
}
} int ans=;
for(rt i=;i<n;i++)
for(rt j=i+;j<=n;j++)(ans+=f[i][j])%=p;
for(rt i=;i<=m;i++)ans=ans*%p;
cout<<ans;
return ;
}

Less than 3

神仙题!

我们在两个01串中的所有“01”结构之间连一条红线,“10”结构之间连一条蓝线

特判$ n \leq 2$之后发现两个01串等价的充要条件是这两个01串的红蓝线一一对应

发现每次改变非边界的数只会导致一条红/蓝线左移一位或右移一位

改变边界上的数可能会导致生成一条新的红/蓝线或使一条红/蓝线消失不见

容易发现移动不能使同一位置有多条线且线的颜色始终保持红蓝对应

我们可以把边界理解为有无限多条颜色交错的红蓝线

枚举上面的每条红线对应下面的每条红线,红线对答案的贡献就是每组相互对应的线的距离和 蓝线同理

数据范围允许暴力枚举对应$ O(n^2)$通过此题

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans,ret;
int a[],b[],t1,t2;
char c[],s[];
int calc(){
t1=t2=;
for(rt i=;i<=n;i++)b[++t2]=;
for(rt i=;i<n;i++)if(c[i]==''&&c[i+]=='')a[++t1]=i;
for(rt i=;i<n;i++)if(s[i]==''&&s[i+]=='')b[++t2]=i;
for(rt i=;i<=n;i++)b[++t2]=n;int nowmin=;
for(rt i=;i<=t2-n+;i++){
int ans=;
for(rt j=;j<i;j++)if(b[j])ans+=b[j];
for(rt j=;j<t1;j++)ans+=abs(a[j+]-b[i+j]);
for(rt j=t1;b[i+j]!=n;j++)ans+=n-b[i+j];
nowmin=min(nowmin,ans);
}
return nowmin;
}
int main(){
n=read();
scanf("%s",c+);scanf("%s",s+);
if(n==&&c[]!=s[])writeln();
else if(n==&&c[]!=s[]&&c[]==c[]&&s[]==s[])writeln();
else {
ret=calc();
for(rt i=;i<=n;i++)c[i]=''+''-c[i],s[i]=''+''-s[i];
ret+=calc();cout<<ret;
}
return ;
}

Permutation and Minimum

正推推不出来的DP题启示我们弃疗倒着推

显然两个位置如果都不是$ -1$就可以扔掉

设有cnt组两个位置都是$ -1$则最终答案需要乘上$ cnt!$因为这些组可以任意交换位置

设$ f[i][j][k]$表示已经填了不小于$ i$的所有数,有$ j$个在序列中出现过的数没有被匹配,有$ k$个在原数列中未出现过的数没有被匹配

假设当前数在原序列出现过则可以匹配一个未出现过的数或自己变成一个未被匹配的数

不能匹配一个出现过的数的原因是假设相邻两个数都不是-1则要被扔掉

假设当前数在原序列中未出现过则可以匹配一个未出现过的数,一个出现过的数或自己成为未被匹配的数

注意如果匹配一个出现过的数有$ j$种匹配方式

直接$ O(n^3)DP$即可

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define p 1000000007
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans;
int a[];bool vis[],nt[];
int q[],t;
int f[][][];
int main(){
n=read();
for(rt i=;i<=*n;i++){
a[i]=read();if(a[i]!=-)vis[a[i]]=;
if(i&^){
if(a[i]==-&&a[i-]==-)cnt++;
if(a[i]!=-&&a[i-]!=-)nt[a[i]]=nt[a[i-]]=;
}
}
for(rt i=;i<=*n;i++)if(!nt[i])if(vis[i])q[++t]=;else q[++t]=;n=t;
//q=1在原数列中
f[n][][]=;
for(rt i=n;i>=;i--){
for(rt j=;j<=n/;j++)
for(rt k=;k<=n/;k++)if(f[i][j][k]){
const int v=f[i][j][k];
if(q[i]){
(f[i-][j+][k]+=v)%=p;
if(k)(f[i-][j][k-]+=v)%=p;
}else {
(f[i-][j][k+]+=v)%=p;
if(k)(f[i-][j][k-]+=v)%=p;
if(j)(f[i-][j-][k]+=1ll*v*j%p)%=p;
}
}
}
int ans=f[][][];
for(rt i=;i<=cnt;i++)ans=1ll*ans*i%p;
cout<<ans;
return ;
}

最新文章

  1. 如何查看Oracle客户端版本
  2. 一张关于docker版本的图
  3. JS根据服务器时间倒计时
  4. linux下svn的co如何排除目录
  5. 关于Spark中RDD的设计的一些分析
  6. Spring mvc 中有关 Shiro 1.2.3 配置问题
  7. 转:MFC 的程序中GetAt()的理解
  8. 有关service
  9. 查看Linux系统下Raid信息
  10. 基于粒子滤波的物体跟踪 Particle Filter Object Tracking
  11. DedeCMS新建模型字段【附件样式】修改方法
  12. (其他)Thinkpad笔记本装系统
  13. Android 开发 框架系列 Android-Universal-Image-Loader 图片加载使用demo
  14. Linux java 命令行编译 jar包
  15. webstorm安装教程
  16. vue中filter的用法
  17. 【转】Vue 2.0封装axios笔记
  18. .core 学习文档
  19. 收集整理的oracle常用命令大全
  20. pycharm中python模板代码自动生成

热门文章

  1. redis对sorted_set进行的相关操作
  2. 【alpha阶段】第十次Scrum Meeting
  3. windows系统中给qt工程添加第三方库
  4. Mysql数据库引擎介绍--转载
  5. Android Studio自定义注释模板
  6. linux下下载安装jdk
  7. sudo: no tty present and no askpass program specified
  8. telnet-server、telnet
  9. Django(七)缓存、信号、Form
  10. 在Asp.Net Core中集成Kafka