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. 用Python做一个翻译软件

    前两天吃了平哥的一波狗粮,他给女朋友写了一个翻译软件,自己真真切切的感受到了程序员的浪漫.在学习requests请求的时候做过类似的Demo,给百度翻译发送一个post请求可以实现任意词组的翻译,利用 ...

  2. Java字符串连接操作的性能问题

    首先,看一段实验程序: package com.test; class StringTest { public static void main(String[] args) { long start ...

  3. 1.VBA 基本概念——《Excel VBA 程序开发自学宝典》

    1.1 常见对象及含义 对象名 含义 application 整个Excel应用程序 window 窗口 worksheet  一个工作表 sheets 指定工作簿的所有工作表的合集 shaperan ...

  4. CHAPTER 24 History of Our Planet 第24章 我们行星的历史

    CHAPTER 24 History of Our Planet 第24章 我们行星的历史 Uncovering the bones of ancient beasts is only part of ...

  5. 安装GNU Radio及相关常用SDR软件的最简单方法

    本文内容.开发板及配件仅限用于学校或科研院所开展科研实验! 淘宝店铺名称:开源SDR实验室 HackRF链接:https://item.taobao.com/item.htm?spm=a1z10.1- ...

  6. easyui的tab标签链接aspx页面引发全局刷新的问题解决方案

    通过tree组件和tabs组件结合加载子页面窗体aspx,点击按钮页面全部重新加载,或整个跳到子窗体页面,解决方案:换一种结合iframe的方式做系统界面:在tree组件出替换掉设置href属性处为下 ...

  7. Digitalocean + ss 搭建加密通信代理服务器

    本文以 DigitalOcean + ss/ssr 配置加密通道***为例,记录了手动搭梯子的过程. 启动一个服务器实例的操作可以参考我的这篇博文,这里主要介绍 ss/ssr 的服务搭建过程. 首先 ...

  8. Ruby知识点二:类

    1.追查对象是否属于某个类时,使用is_a?方法  追查某个对象属于哪个类时,使用class方法 判断某个对象是否属于某个类时,使用instance_of?方法 判断类是否包含某个模块,使用inclu ...

  9. Bitcoin Core P2P网络层

    目录 数据结构 节点发现和节点连接 地址管理 节点发现 节点连接 插口(Sockets)和消息 Socket线程 (net.cpp) 消息线程 ProcessMessages (net_process ...

  10. 手机访问本地php项目遇到的问题及解决

    做html5的本地应用要调试后台,学了下php 按照和连j2ee的时候一样,电脑发射wifi,ipconfig..等等  发现tomcat的可以访问,apache的不能访问,搜索好久,没找到解答, j ...