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类与对象的组合与继承

    1.把类的对象实例化放到一个新的类里面叫做类的组合,组合就是指几个横向关系的类放在一起,纵向关系的类放在一起是继承,根据实际应用场景确定.简单的说,组合用于“有一个”的场景中,继承用于“是一个”的场景 ...

  2. UNITY_委托和事件

    UNITY_委托和事件 参考资料: Unity3D脚本编程-使用C#语言开发跨平台游戏-陈嘉栋 观察者模式 主题(Subject)管理某些数据,当主题的数据发生改变时,会通知已经注册(Register ...

  3. GIT问题(一)——push冲突

  4. Spark概述及集群部署

    Spark概述 什么是Spark (官网:http://spark.apache.org) Spark是一种快速.通用.可扩展的大数据分析引擎,2009年诞生于加州大学伯克利分校AMPLab,2010 ...

  5. springboot通过http访问——修改访问的端口号

    文章转载来于:https://blog.csdn.net/zknxx/article/details/53433592 有时候我们可能需要启动不止一个SpringBoot,而SpringBoot默认的 ...

  6. GC知识随笔

    1.  http://blog.csdn.net/column/details/14851.html   地址记录 2.关于Minor GC,Major GC与Full GC 1)  Minor GC ...

  7. Django_rest_framework_Serializer

    序列化Serializer 序列化用于对用户请求数据进行验证和数据进行序列化(为了解决queryset序列化问题). 那什么是序列化呢?序列化就是把对象转换成字符串,反序列化就是把字符串转换成对象 m ...

  8. C++ Style Languages: C++, Objective-C, Java, C#

    Hyperpolyglot.org From Hyperpolyglot.org C++ Style Languages: C++, Objective-C, Java, C# a side-by-s ...

  9. CSS命名规范(规则)常用的CSS命名规则

    CSS命名规范(规则)常用的CSS命名规则   CSS命名规范(规则)常用的CSS命名规则   头:header   内容:content/container   尾:footer ...

  10. 团队项目-NABCD

    用户需求分析与NABCD 模拟经营类(SIM)游戏:玩家模拟经营一家软件公司,平台初步定为Android. Need需求 任何一款游戏都要有自己的定位和目标群体,这些 iiMediaResearch数 ...