AtCoder Grand Contest 003

A - Wanna go back home

翻译

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

题解

什么逗逼东西。。。

  1. #include<cstdio>
  2. #include<cstring>
  3. using namespace std;
  4. char s[1010];
  5. bool W,E,S,N;
  6. int main()
  7. {
  8. scanf("%s",s+1);
  9. 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';
  10. if((W^E)||(N^S))puts("No");else puts("Yes");
  11. return 0;
  12. }

B - Simplified mahjong

翻译

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

题解

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

  1. #include<iostream>
  2. #include<cstdio>
  3. using namespace std;
  4. #define MAX 100100
  5. #define ll long long
  6. int a[MAX],n;
  7. ll ans;
  8. int main()
  9. {
  10. cin>>n;
  11. for(int i=1;i<=n;++i)cin>>a[i];
  12. for(int i=1;i<=n;++i)
  13. {
  14. ans+=a[i]/2,a[i]%=2;
  15. if(a[i]&&a[i+1])++ans,--a[i+1];
  16. }
  17. printf("%lld\n",ans);
  18. return 0;
  19. }

C - BBuBBBlesort!

翻译

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

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

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

题解

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

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. using namespace std;
  8. #define MAX 100100
  9. inline int read()
  10. {
  11. int x=0;bool t=false;char ch=getchar();
  12. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  13. if(ch=='-')t=true,ch=getchar();
  14. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  15. return t?-x:x;
  16. }
  17. int n,a[MAX],b[MAX],ans;
  18. int main()
  19. {
  20. n=read();
  21. for(int i=1;i<=n;++i)b[i]=a[i]=read();
  22. sort(&b[1],&b[n+1]);
  23. for(int i=1;i<=n;++i)a[i]=lower_bound(&b[1],&b[n+1],a[i])-b;
  24. for(int i=1;i<=n;++i)ans+=abs(a[i]-i)&1;
  25. printf("%d\n",ans>>1);
  26. return 0;
  27. }

D - Anticube

翻译

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

题解

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

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

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. #include<map>
  9. using namespace std;
  10. #define ll long long
  11. #define MAX 100100
  12. inline ll read()
  13. {
  14. ll x=0;bool t=false;char ch=getchar();
  15. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  16. if(ch=='-')t=true,ch=getchar();
  17. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  18. return t?-x:x;
  19. }
  20. map<ll,int> M,vis;
  21. int n,tot,ans;
  22. ll a[MAX],b[MAX],p[MAX],pri[MAX];
  23. int main()
  24. {
  25. n=read();
  26. for(int i=1;i<=n;++i)a[i]=read();
  27. for(int i=2;i<=2500;++i)
  28. {
  29. bool fl=true;
  30. for(int j=2;j<i;++j)if(i%j==0){fl=false;break;}
  31. if(fl)pri[++tot]=i;
  32. }
  33. for(int i=1;i<=n;++i)
  34. {
  35. p[i]=b[i]=1;
  36. for(int j=1;j<=tot&&a[i]>1;++j)
  37. if(a[i]%pri[j]==0)
  38. {
  39. int cnt=0;
  40. while(a[i]%pri[j]==0)a[i]/=pri[j],++cnt;
  41. cnt%=3;if(!cnt)continue;
  42. if(cnt==1)p[i]*=1ll*pri[j]*pri[j],b[i]*=pri[j];
  43. else p[i]*=pri[j],b[i]*=1ll*pri[j]*pri[j];
  44. }
  45. if(a[i]==1)continue;
  46. ll s=sqrt(a[i]);b[i]*=a[i];
  47. if(s*s==a[i])p[i]*=s;
  48. else p[i]*=a[i]*a[i];
  49. }
  50. for(int i=1;i<=n;++i)++M[b[i]];
  51. for(int i=1;i<=n;++i)
  52. {
  53. if(vis[b[i]])continue;
  54. if(b[i]!=p[i])ans+=max(M[b[i]],M[p[i]]);
  55. else ans+=1;
  56. vis[b[i]]=vis[p[i]]=1;
  57. }
  58. printf("%d\n",ans);
  59. return 0;
  60. }

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)\)。

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

代码是这样的

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. using namespace std;
  9. #define ll long long
  10. #define MAX 100100
  11. inline ll read()
  12. {
  13. ll x=0;bool t=false;char ch=getchar();
  14. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  15. if(ch=='-')t=true,ch=getchar();
  16. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  17. return t?-x:x;
  18. }
  19. int n,Q,tot;
  20. ll q[MAX],ans[MAX],s[MAX];
  21. void Solve(ll k,int x,ll l)
  22. {
  23. if(!k||!l)return;
  24. if(x==1){ans[n]+=k*(l/n);ans[l%n]+=k;return;}
  25. Solve(l/q[x-1]*k,x-1,q[x-1]);
  26. Solve(k,x-1,l%q[x-1]);
  27. }
  28. int main()
  29. {
  30. n=read();Q=read();
  31. for(int i=1;i<=Q;++i)
  32. {
  33. ll x=read();
  34. while(tot&&q[tot]>=x)--tot;
  35. q[++tot]=x;
  36. }
  37. Q=tot;q[0]=n;Solve(1,Q,q[Q]);
  38. for(int i=n;i;--i)ans[i]+=ans[i+1];
  39. for(int i=1;i<=n;++i)printf("%lld\n",ans[i]);
  40. return 0;
  41. }

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

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

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. using namespace std;
  9. #define ll long long
  10. #define MAX 100100
  11. inline ll read()
  12. {
  13. ll x=0;bool t=false;char ch=getchar();
  14. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  15. if(ch=='-')t=true,ch=getchar();
  16. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  17. return t?-x:x;
  18. }
  19. int n,Q,tot;
  20. ll q[MAX],ans[MAX],s[MAX];
  21. int Binary(int l,int r,ll k)
  22. {
  23. int ret=0;
  24. while(l<=r)
  25. {
  26. int mid=(l+r)>>1;
  27. if(k>=q[mid])l=mid+1,ret=mid;
  28. else r=mid-1;
  29. }
  30. return ret;
  31. }
  32. int main()
  33. {
  34. n=read();Q=read();q[tot=1]=n;
  35. for(int i=1;i<=Q;++i)
  36. {
  37. ll x=read();
  38. while(tot&&q[tot]>=x)--tot;
  39. q[++tot]=x;
  40. }
  41. Q=tot;s[Q]=1;
  42. for(int i=Q;i;--i)
  43. {
  44. ll l=q[i];int p=Binary(1,i-1,l);
  45. while(p)s[p]+=l/q[p]*s[i],l%=q[p],p=Binary(1,p-1,l);
  46. ans[l]+=s[i];
  47. }
  48. for(int i=n;i;--i)ans[i]+=ans[i+1];
  49. for(int i=1;i<=n;++i)printf("%lld\n",ans[i]);
  50. return 0;
  51. }

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\)。

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

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. using namespace std;
  9. #define ll long long
  10. #define MOD 1000000007
  11. #define MAX 1010
  12. struct Matrix
  13. {
  14. int s[3][3];
  15. void clear(){memset(s,0,sizeof(s));}
  16. void init(){clear();s[1][1]=s[2][2]=1;}
  17. int* operator[](int x){return s[x];}
  18. }ans;
  19. Matrix operator*(Matrix a,Matrix b)
  20. {
  21. Matrix ret;ret.clear();
  22. for(int i=1;i<=2;++i)
  23. for(int j=1;j<=2;++j)
  24. for(int k=1;k<=2;++k)
  25. ret[i][j]=(ret[i][j]+1ll*a[i][k]*b[k][j])%MOD;
  26. return ret;
  27. }
  28. Matrix fpow(Matrix a,ll b)
  29. {
  30. Matrix s;s.init();
  31. while(b){if(b&1)s=s*a;a=a*a;b>>=1;}
  32. return s;
  33. }
  34. ll K;
  35. int h,w,s,t1,t2,p1,p2;
  36. char g[MAX][MAX];
  37. int fpow(int a,int b)
  38. {
  39. int s=1;
  40. while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
  41. return s;
  42. }
  43. int main()
  44. {
  45. cin>>h>>w>>K;if(K<=1){puts("1");return 0;}
  46. for(int i=1;i<=h;++i)
  47. {
  48. scanf("%s",g[i]+1);
  49. for(int j=1;j<=w;++j)
  50. s+=g[i][j]=='#';
  51. }
  52. for(int i=1;i<=h;++i)
  53. if(g[i][1]=='#'&&g[i][w]=='#')++p1;
  54. for(int i=1;i<=w;++i)
  55. if(g[1][i]=='#'&&g[h][i]=='#')++p2;
  56. for(int i=1;i<=h;++i)
  57. for(int j=1;j<=w;++j)
  58. if(g[i][j]=='#')
  59. {
  60. if(j>1&&g[i][j-1]=='#')++t1;
  61. if(i>1&&g[i-1][j]=='#')++t2;
  62. }
  63. if(!p1&&!p2){printf("%d\n",fpow(s,(K-1)%(MOD-1)));return 0;}
  64. if(p1&&p2){puts("1");return 0;}
  65. if(!p1)swap(p1,p2),swap(t1,t2);
  66. ans[1][1]=s;ans[1][2]=0;ans[2][1]=t1;ans[2][2]=p1;
  67. ans=fpow(ans,K-1);
  68. printf("%d\n",(ans[1][1]-ans[2][1]+MOD)%MOD);
  69. return 0;
  70. }

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. c语言数字图像处理(四):灰度变换

    灰度变换 灰度变换函数 s = T(r)   其中r为输入图像在(x, y)点处的灰度值,s为输出图像在(x, y)点处的灰度值 灰度变换的作用 上图所示的两幅T(s)函数的图像曲线,第一幅图可以增强 ...

  2. java基础---类加载和对象创建过程

    类中可以存在的成员: class A{ 静态成员变量: 非静态成员变量: 静态函数: 非静态函数: 构造函数 A(..){...} 静态代码块 static{...} 构造代码块 {...} } 类加 ...

  3. tomcat 项目的搭建-【Linux】

  4. appium+python+unittest 测试用例的几种加载执行方式

    利用python进行测试时,测试用例的加载方式有2种: 一种是通过unittest.main()来启动所需测试的测试模块:  一种是添加到testsuite集合中再加载所有的被测试对象,而testsu ...

  5. 【坚持】Selenium+Python学习记录 DAY9

    2018/05/29 [来源:菜鸟教程](http://www.runoob.com/python3/python3-examples.html) 运算符重载 https://segmentfault ...

  6. Python 3 利用 Dlib 19.7 进行人脸检测

    0. 引言 / Overview 介绍 Dlib 中基于 HOG,Histogram of Oriented Gradients / 方向梯度直方图 实现 Face Detect / 人脸检测 的两个 ...

  7. Visual Studio的框选代码区块功能

    要从Visual Studio里复制代码粘贴到其他地方,会因为对齐的问题,造成粘贴的时候,代码左边带有大量的空格. 而VS有一个很好的功能就是框选功能,使用方法是,将光标放置在要框选代码的最左边,然后 ...

  8. Tomcat部署与使用

    Tomcat简介 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Sun和其他一些公司及个人共同开发 ...

  9. tac命令详解

    基础命令学习目录首页 原文链接:http://blog.chinaunix.net/uid-128922-id-289974.html 有许多命令都可以查看文件,不同的命令有不同的优点,可以针对不同的 ...

  10. nice和renice命令详解

    基础命令学习目录首页 进程调度是linux中非常重要的概念.linux内核有一套高效复杂的调度机制,能使效率极大化,但有时为了实现特定的要求,需要一定的人工干预.比如,你希望操作系统能分配更多的CPU ...