AtCoder Grand Contest 003

A - Wanna go back home

翻译

告诉你一个人每天向哪个方向走,你可以自定义他每天走的距离,问它能否在最后一天结束之后回到起点。

题解

什么逗逼东西。。。

#include<cstdio>
#include<cstring>
using namespace std;
char s[1010];
bool W,E,S,N;
int main()
{
scanf("%s",s+1);
for(int i=1,l=strlen(s+1);i<=l;++i)W|=s[i]=='W',E|=s[i]=='E',S|=s[i]=='S',N|=s[i]=='N';
if((W^E)||(N^S))puts("No");else puts("Yes");
return 0;
}

B - Simplified mahjong

翻译

你有写着\([1,n]\)的卡片若干张,写着\(i\)的有\(a_i\)张,两两卡片可以配对当且仅当它们上面写的数字差的绝对值小于等于\(1\),求最大配对数。

题解

什么鬼玩意。。。。然而yyb怒交4发才AC

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 100100
#define ll long long
int a[MAX],n;
ll ans;
int main()
{
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<=n;++i)
{
ans+=a[i]/2,a[i]%=2;
if(a[i]&&a[i+1])++ans,--a[i+1];
}
printf("%lld\n",ans);
return 0;
}

C - BBuBBBlesort!

翻译

给定一个序列\(a\),元素两两不同,可以使用两种操作。

  • 1.翻转相邻两个元素
  • 2.翻转相邻三个元素

求最少用几次1操作能够将序列排好序。

题解

第一个操作等价于交换\((i,i+1)\),第二个操作等价于交换\((i,i+2)\)。那么第一个操作会改变位置奇偶性,而第二个操作不会。计算一下有几个数需要改变奇偶性,最终答案就是他们的个数除二,因为每次可以改变一对数的奇偶性。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAX 100100
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,a[MAX],b[MAX],ans;
int main()
{
n=read();
for(int i=1;i<=n;++i)b[i]=a[i]=read();
sort(&b[1],&b[n+1]);
for(int i=1;i<=n;++i)a[i]=lower_bound(&b[1],&b[n+1],a[i])-b;
for(int i=1;i<=n;++i)ans+=abs(a[i]-i)&1;
printf("%d\n",ans>>1);
return 0;
}

D - Anticube

翻译

给定\(n\)个数,要求选出最多的数,满足任意两个数的乘积都不是完全立方数。

题解

把每个数分解质因数之后,所有指数模\(3\),那么现在显然如果一个数能够乘上另外一个数变成完全立方数,那么它分解之后指数模\(3\)的结果必然是固定的。并且是两两配对的关系,因此,从配对的集合中选择较大的那个即可。

然后就考虑怎么分解质因数,首先如果不想动脑子直接\(Pollard-rho\)。稍微动点脑子的话就是这样子:首先先用三次方根以内的所有质数分解,那么剩下的部分最多只有两个质因子,那么这两个质因子要么相同要么不同,直接判一下就好了。然后似乎就很简单了?

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
#define ll long long
#define MAX 100100
inline ll read()
{
ll x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
map<ll,int> M,vis;
int n,tot,ans;
ll a[MAX],b[MAX],p[MAX],pri[MAX];
int main()
{
n=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=2;i<=2500;++i)
{
bool fl=true;
for(int j=2;j<i;++j)if(i%j==0){fl=false;break;}
if(fl)pri[++tot]=i;
}
for(int i=1;i<=n;++i)
{
p[i]=b[i]=1;
for(int j=1;j<=tot&&a[i]>1;++j)
if(a[i]%pri[j]==0)
{
int cnt=0;
while(a[i]%pri[j]==0)a[i]/=pri[j],++cnt;
cnt%=3;if(!cnt)continue;
if(cnt==1)p[i]*=1ll*pri[j]*pri[j],b[i]*=pri[j];
else p[i]*=pri[j],b[i]*=1ll*pri[j]*pri[j];
}
if(a[i]==1)continue;
ll s=sqrt(a[i]);b[i]*=a[i];
if(s*s==a[i])p[i]*=s;
else p[i]*=a[i]*a[i];
}
for(int i=1;i<=n;++i)++M[b[i]];
for(int i=1;i<=n;++i)
{
if(vis[b[i]])continue;
if(b[i]!=p[i])ans+=max(M[b[i]],M[p[i]]);
else ans+=1;
vis[b[i]]=vis[p[i]]=1;
}
printf("%d\n",ans);
return 0;
}

E - Sequential operations on Sequence

翻译

给定一个长度为\(n\)的数列,一开始就是\(1,2,...,n\),有\(m\)次操作,每次给定一个参数\(q_i\),首先把数列无限倍长,然后只取前\(q_i\)个数作为新的数列。求所有操作做完之后每个数出现了几次。

题解

深思熟虑一下,发现真正有用的位置一定是一个单增的序列。我们设\(S(i,l)\)表示第\(i\)个操作的前\(l\)位。

那么,有这样一个转移:\(S(i,l)=[\frac{l}{q_{i-1}}]*S(i-1,q[i-1])+S(i-1,l\%q_{i-1})\)

那么,当\(l<q_{i-1}\)时,显然有\(S(i,l)=S(i-1,l)\)。

然后这样子就可以写成递归形式的暴力。

代码是这样的

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
inline ll read()
{
ll x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,Q,tot;
ll q[MAX],ans[MAX],s[MAX];
void Solve(ll k,int x,ll l)
{
if(!k||!l)return;
if(x==1){ans[n]+=k*(l/n);ans[l%n]+=k;return;}
Solve(l/q[x-1]*k,x-1,q[x-1]);
Solve(k,x-1,l%q[x-1]);
}
int main()
{
n=read();Q=read();
for(int i=1;i<=Q;++i)
{
ll x=read();
while(tot&&q[tot]>=x)--tot;
q[++tot]=x;
}
Q=tot;q[0]=n;Solve(1,Q,q[Q]);
for(int i=n;i;--i)ans[i]+=ans[i+1];
for(int i=1;i<=n;++i)printf("%lld\n",ans[i]);
return 0;
}

发现在\(Solve\)的递归过程中,以任何一个位置开始的第二个递归,也就是取模的那个,模的次数不会超过\(log\),这样子可以提前把取模的时候,下一个能够取模的位置的贡献给算好,这个可以二分解决。

然后把所有后面提供的倍数的贡献合在一起算,这样子单次的复杂度也对了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
inline ll read()
{
ll x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,Q,tot;
ll q[MAX],ans[MAX],s[MAX];
int Binary(int l,int r,ll k)
{
int ret=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(k>=q[mid])l=mid+1,ret=mid;
else r=mid-1;
}
return ret;
}
int main()
{
n=read();Q=read();q[tot=1]=n;
for(int i=1;i<=Q;++i)
{
ll x=read();
while(tot&&q[tot]>=x)--tot;
q[++tot]=x;
}
Q=tot;s[Q]=1;
for(int i=Q;i;--i)
{
ll l=q[i];int p=Binary(1,i-1,l);
while(p)s[p]+=l/q[p]*s[i],l%=q[p],p=Binary(1,p-1,l);
ans[l]+=s[i];
}
for(int i=n;i;--i)ans[i]+=ans[i+1];
for(int i=1;i<=n;++i)printf("%lld\n",ans[i]);
return 0;
}

F - Fraction of Fractal

翻译

LOJ

题解

首先给定了条件,满足所有黑格子都是四联通。那么图形在分形之后,我们考虑两个块的黑白格子是否联通,唯一需要考虑的就是某一行(列)在第一列(行)以及最后一列(行)是否同时有一个黑格子,如果有的话,那么这一侧的两个联通块是可以联通的。这么说可能不太清楚,按照网上的说法再写一遍。我们定义如果某一行在第一列和最后一列都是黑格子,则我们称之为一个左右接口。同理,对于某一列而言,如果在第一行和最后一行都是黑格子,我们称之为上下接口。

先考虑特殊情况,如果既没有左右接口,也没有上下接口,显然每一个单独的图就是一个联通块,这个直接快速幂即可,也就是\(s^{k-1}\),\(s\)是黑格子的数量。如果既有左右接口,又有上下接口,显然答案就是\(1\)。

抛去这两种情况,剩下的显然就是只有左右接口或者上下接口中的一个。然而这两种情况是一样的(你把整个图形旋转\(90°\)就好了)。我们现在只考虑上下接口,那么显然最终的联通块都是类似于一条条的链的组成。至于怎么计算链的个数?我们可以用总共的点数减去链接在了一起的联通块的个数,这样就是链的个数了(神仙啊)。

这样子以来,我们认为一级分形图,即初始图为1个节点,每次增加一级的时候,我们认为将原先所有的黑格子用一个一级分形图代替。设\(V_k\)表示点数,\(E_k\)表示边数,假设存在的、满足连续的两个上下格子都是黑色的对数为\(c\),上下接口数为\(ud\)。那么可以得到递推式\(V_k=V_{k-1}*s\),\(E_k=E_{k-1}*s+c*ud_k\)。

关于点数的递推很好理解,就是每次因为是替代关系,所以点数直接翻倍。

边数的关系是这样来的,首先当前每个图形中有\(E_{k-1}\)条边,然后分形之后重复了\(s\)次,所以这一部分的贡献是\(s*E_{k-1}\)。另外一部分贡献是新的联通块通过上下接口连接在一起形成的新的边数,那么,这里贡献的边数是\(c*ud_k\),即对于每个上下相邻的\(k-1\)层图,我们会贡献\(ud_k\)条边,而\(ud_k\)的含义是当前是第\(k\)层分形图的时候上下接口的个数,\(ud_k\)显然等于\(ud^k\)。

那么直接矩阵快速幂就好了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MOD 1000000007
#define MAX 1010
struct Matrix
{
int s[3][3];
void clear(){memset(s,0,sizeof(s));}
void init(){clear();s[1][1]=s[2][2]=1;}
int* operator[](int x){return s[x];}
}ans;
Matrix operator*(Matrix a,Matrix b)
{
Matrix ret;ret.clear();
for(int i=1;i<=2;++i)
for(int j=1;j<=2;++j)
for(int k=1;k<=2;++k)
ret[i][j]=(ret[i][j]+1ll*a[i][k]*b[k][j])%MOD;
return ret;
}
Matrix fpow(Matrix a,ll b)
{
Matrix s;s.init();
while(b){if(b&1)s=s*a;a=a*a;b>>=1;}
return s;
}
ll K;
int h,w,s,t1,t2,p1,p2;
char g[MAX][MAX];
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
int main()
{
cin>>h>>w>>K;if(K<=1){puts("1");return 0;}
for(int i=1;i<=h;++i)
{
scanf("%s",g[i]+1);
for(int j=1;j<=w;++j)
s+=g[i][j]=='#';
}
for(int i=1;i<=h;++i)
if(g[i][1]=='#'&&g[i][w]=='#')++p1;
for(int i=1;i<=w;++i)
if(g[1][i]=='#'&&g[h][i]=='#')++p2;
for(int i=1;i<=h;++i)
for(int j=1;j<=w;++j)
if(g[i][j]=='#')
{
if(j>1&&g[i][j-1]=='#')++t1;
if(i>1&&g[i-1][j]=='#')++t2;
}
if(!p1&&!p2){printf("%d\n",fpow(s,(K-1)%(MOD-1)));return 0;}
if(p1&&p2){puts("1");return 0;}
if(!p1)swap(p1,p2),swap(t1,t2);
ans[1][1]=s;ans[1][2]=0;ans[2][1]=t1;ans[2][2]=p1;
ans=fpow(ans,K-1);
printf("%d\n",(ans[1][1]-ans[2][1]+MOD)%MOD);
return 0;
}

AtCoder Grand Contest 003的更多相关文章

  1. AtCoder Grand Contest 003 D - Anticube

    题目传送门:https://agc003.contest.atcoder.jp/tasks/agc003_d 题目大意: 给定\(n\)个数\(s_i\),要求从中选出尽可能多的数,满足任意两个数之积 ...

  2. AtCoder Grand Contest 003 E - Sequential operations on Sequence

    题目传送门:https://agc003.contest.atcoder.jp/tasks/agc003_e 题目大意 一串数,初始为\(1\sim N\),现有\(Q\)个操作,每次操作会把数组长度 ...

  3. AtCoder Grand Contest 003 F - Fraction of Fractal

    题目传送门:https://agc003.contest.atcoder.jp/tasks/agc003_f 题目大意: 给定一个\(H×W\)的黑白网格,保证黑格四连通且至少有一个黑格 定义分形如下 ...

  4. Atcoder Grand Contest 003 F - Fraction of Fractal(矩阵乘法)

    Atcoder 题面传送门 & 洛谷题面传送门 Yet another AGC F,然鹅这次就没能自己想出来了-- 首先需注意到题目中有一个条件叫做"黑格子组成的连通块是四联通的&q ...

  5. [Atcoder Grand Contest 003] Tutorial

    Link: AGC003 传送门 A: 判断如果一个方向有,其相反方向有没有即可 #include <bits/stdc++.h> using namespace std; ]; map& ...

  6. AtCoder Grand Contest 003题解

    传送门 \(A\) 咕咕 const int N=1005; char s[N];int val[N],n; int main(){ scanf("%s",s+1),n=strle ...

  7. AtCoder Grand Contest 012

    AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...

  8. AtCoder Grand Contest 011

    AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...

  9. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

随机推荐

  1. LinuxMint 18.3禁用ipv6

    编辑/etc/sysctl.conf文件,添加如下内容 net.ipv6.conf.all.disable_all = 1 保存后执行 sudo sysctl -p 即可生效

  2. 005 -- Mysql数据库引擎特点分析

    常用的数据库引擎的特点: ISAM: ISAM是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到数据库查询次数要远大于更新次数.因此,ISAM执行读取操作的速度很快,而且不占用大量的 ...

  3. 2018爆零记第二弹之day0

    话说初赛水了个70分,ε=(´ο`*)))唉,还是太菜了. 今天两点左右到了电子科大对面宾馆,收拾安顿好后又去电子科大踩点. 进门又走过了不长不短的水杉道,来到了不大不小的西湖(为什么是这个名字... ...

  4. ossec兼容的操作系统

    OSSEC兼容以下操作系统和日志格式 操作系统 以下操作系统可安装OSSEC代理 l  GNU/Linux (all distributions, including RHEL, Ubuntu, Sl ...

  5. Python-opencv摄像头图像捕获

    实例一 (灰色调度) #!/usr/bin/env python # _*_ coding:utf-8 _*_ import cv2 as cv import numpy as np capture ...

  6. java程序设计课程实验报告1

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计   班级:1353       姓名:陈都  学号:20135328 成绩:             指导 ...

  7. 如何知道一个App的包名呢

    包名(Package name)是Android系统中判断一个APP的唯一标识 记录我获取包名的几种方式 方法一:通过cmd命令,打开你要获取包名的APP 1.adb shell 2.dumpsys ...

  8. Task 6.2冲刺会议七 /2015-5-20

    今天把主界面改善了一下,主要功能时摄像头的使用以及语音聊天的部分,两个部分的设计原理基本相同,但是可是好几个模块让有点不知道该怎么下手.这时候我感觉到了模块拼接是很困难的,只有十分清楚每个模块才能很好 ...

  9. java的小学生四则运算

    import java.awt.*; import java.awt.event.*; import java.io.FileNotFoundException; import java.io.IOE ...

  10. 为什么使彩色图变灰RGB的权重会固定(R:0.299 G:0.587 B:0.114)?

    人眼对绿色的敏感度最高,对红色的敏感度次之,对蓝色的敏感度最低,因此使用不同的权重将得到比较合理的灰度图像.根据实验和理论推导得出以下数值 R: 0.299. G:  0.587. B: 0.114.