[Atcoder]test023(STL+hash)

18 篇文章 0 订阅

A

我是超链接

题意:

连续数字和为0的序列个数

题解:

直接用map的前缀和计数就行,不用忘记开longlong

代码:

#include <cstdio>
#include <map>
#define LL long long
using namespace std;
const int N=200005;
int n,a[N];map<LL,LL>mp;
int main()
{
    scanf("%d",&n);
    mp[0]=1;LL sum=0,ans=0;
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum+=(LL)a[i];ans+=mp[sum];
        mp[sum]++;
    } 
    printf("%lld",ans);
}

B

我是超链接

题意:

A表示向下平移,B表示向右平移,剩下的看样例解释吧

题解:

我枚举的A,然后把矩阵copy一份,计算出行和列的hash值,这样再枚举B的话就可以直接判断了
check是O(n)的,只需要判断第i行的hash值和第i列的hash值都相等就可以了
然后枚举B都是O(n)的转移,把每一行的hash值平移,即abc变成cab,这个转移是O(1)的,每一行都往后平移,那么是O(n)的
列的话整列是不变的,只需要平移就好
总时间复杂度O(n^3)

代码:

#include <cstdio>
#define LL long long  
using namespace std;
const int mod=19260817;
const int base=31;
const int N=305;
char a[N][N],st[N],copy[N][N];
int hashA[N],hashB[N],hashC[N];
LL ksm(LL a,LL k)
{
    LL ans=1;
    for (;k;k>>=1,a=a*a%mod)
      if (k&1) ans=ans*a%mod;
    return ans;
}
int main()
{
    int n;scanf("%d",&n);int ans=0;
    for (int i=1;i<=n;i++)
    {
        scanf("%s",st+1);
        for (int j=1;j<=n;j++) a[i][j]=st[j];
    }
    LL inv=ksm(base,mod-2);
    LL what=ksm(base,n-1);
    for (int A=0;A<n;A++)
    {
        for (int i=1;i<=n;i++)
          for (int j=1;j<=n;j++) 
            copy[(i+A-1+n)%n+1][j]=a[i][j],hashA[i]=0,hashB[i]=0;

        for (int i=1;i<=n;i++)
          for (int j=1;j<=n;j++) 
          {
            hashB[i]=(hashB[i]*base%mod+copy[j][i])%mod;
            hashA[i]=(hashA[i]*base%mod+copy[i][j])%mod;
          }

        for (int B=1;B<=n;B++)
        {
            bool fff=1;
            for (int i=1;i<=n;i++)
              if (hashA[i]!=hashB[i]) {fff=0;break;} 
            if (fff) ans++;
            for (int i=1;i<=n;i++)
              hashA[i]=((hashA[i]-copy[i][n-B+1]+mod)*inv%mod+copy[i][n-B+1]*what%mod)%mod;
            int t=hashB[n];
            for (int i=n;i>=2;i--)
              hashB[i]=hashB[i-1];
            hashB[1]=t; 
        }
    }
    printf("%d",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值