处女座和小姐姐(二)

【题目描述】

课上处女座成功将纸条传给了小姐姐,约下午和小姐姐一起逛街。他们坐在公交车上一起欣赏窗外的广告牌,每一个广告牌都有一个编号,而处女座的视野范围是有限的,每次只能看到连续的p个广告牌。由于处女座是数学大师,他用O(1)的时间算出来了他看到的广告牌编号的积mod P的值并记录了下来,直到坐车到了商场。

商场里有定制手环的地方,他可以定制一个长度为k的手环,但是选号是收费的,而处女座把家教挣来的钱都用于外出打比赛了,于是他决定自己挑号。

他把之前路上记下来数字按先从左往右,再从上到下的顺序排成一个n*m的矩阵,他想从中选出一条长度为k的路径,使得路径上的数在mod k的意义上各不相同(每个点只和他的上下左右相邻),从而作为他选的号码。

现在处女座想知道,他有多少条路径可以选择(不忽视顺序,(2,2)->(2,1)和(2,1)->(2,2)会被视为两条路径)。

【输入描述】

输入数据共包括两行,第一行包括四个整数n,m,p,P,k,其中p为处女座一次能看到的连续广告牌的数量,其他字母含义如描述所示。

第二行包括四个整数a0,x,y,z,对于每个广告牌而言,他的编号是ai=x∗ai−12+y∗ai−1+z。广告牌从a1开始到an∗m+p−1为止。

1≤n,m≤20
1≤k≤min(20,n∗m)
1≤p≤106
1≤A0,P,X,Y,Z≤1,000,000,000

【输出描述】

一个整数,表示可以选择的路径数量。

【样例】

示例1

输入
2 2 1 2 2
1 0 1 1
输出
4
说明
a1=2,a2=3,a3=4,a4=5 

所以2*2的矩阵是:

0 1

0 1

因此可行方案有(1,1)->(1,2),(1,2)->(1,1),(2,1)->(2,2),(2,2)->(2,1)共4种

思路:

问题可以分成两个子问题,首先是求一个数组连续 p 个数 mod p 的乘积,其次是找出长度为 k 的符合条件的链的个数

对于第一个问题,可以将序列按照长度 m 进行分段,每段分别计算前缀和后缀乘积,这样任意位置的答案可以看成前段的后缀与后短的乘积拼出

对于第二个问题,可以用 dfs 进行搜索,但由于 (400*3)^20 显然会 TLE,因此可进行双向优化,枚举起点然后双向 dfs,一次向两边进行搜索,故而时间复杂度可降到 400*(2*3)^10,此外,可以使用状压的方式来记录状态

【源代码】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define PI acos(-1.0)
#define E 1e-6
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define N 2000001
#define LL long long
using namespace std;
LL n,m,p,P,k;
LL a[N],b[N],temp[N];
LL X,Y,Z;
LL res;
LL G[101][101];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
void dfs(int x,int y,int cnt,int ans,int sum,bool flag)
{
    if(cnt==sum){
        if(!flag)
            temp[ans>>1]++;
        if(flag)
            res+=temp[(((1<<(k+1))-1)^ans)>>1];
        return;
    }
    for(int i=0;i<4;i++){
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(ans&(1<<G[nx][ny]))
            continue;
        dfs(nx,ny,cnt+1,ans|(1<<G[nx][ny]),sum,flag);
    }
}
int main(){
    scanf("%lld%lld%lld%lld%lld",&n,&m,&p,&P,&k);
    scanf("%lld%lld%lld%lld",&a[0],&X,&Y,&Z);

    for(int i=1;i<=n*m+p-1;i++)//前缀
        a[i]=(a[i-1]*a[i-1]%P * X%P + a[i-1]*Y%P + Z )%P;

    int cnt=0;//标号
    int pos=0;//位置
    for(int i=p;i<=n*m+p-1;i++){//后缀
        res=res*a[i]%P;
        if(i-p+1>pos){
            res=1;
            pos=i;
            b[i]=a[i];
            for(int j=i-1;j>=i-p+1;j--)
                b[j]=b[j+1]*a[j]%P;
        }
        temp[++cnt]=(LL)b[i-p+1]*res%P;
    }

    int cur=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            G[i][j]=temp[++cur]%k+1;


    res=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            memset(temp,0,sizeof(temp));

            //双向优化搜索
            dfs(i,j,1,1|(1<<G[i][j]),k/2,false);
            dfs(i,j,1,1,k/2+k%2+1,true);
        }
    }

    if(n==1&&m==1)
        res=1;

    printf("%lld\n",res);

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
小姐姐跳舞源码是一个使用PHP编写的源码,用于展示一个小姐姐优美舞蹈的网页。该源码主要分为前端和后端两个部分。 前端部分使用HTML和CSS来构建页面的布局和样式。通过HTML的标签和属性,可以创建网页的基本结构,如标题、导航栏、舞蹈视频等。而CSS则可以控制网页中元素的样式和排列,例如字体、颜色、背景等。通过精心设计的布局和美化,可以使整个页面看起来更加美观动人。 后端部分则使用PHP来处理网页的动态内容和交互。通过PHP的处理,可以从数据库中获取舞蹈视频的链接和相关信息,并将其展示在页面中。同时,PHP还可以实现用户的交互功能,如评论、点赞等。通过与数据库和用户的交互,可以实现小姐姐跳舞源码的更多功能和特性。 通过将前端和后端结合起来,小姐姐跳舞源码可以实现一个完整的网页应用。用户可以在页面中观看小姐姐的舞蹈视频,与其他用户进行交流和互动。而开发者可以根据自己的需求和设计理念,对源码进行修改和扩展,以实现更多个性化的功能和效果。 总而言之,小姐姐跳舞源码是一个基于PHP的网页源码,通过前端和后端的协作,展示了一个优美舞蹈的网页,并提供了与用户交互的功能。这个源码可以作为学习和实践PHP编程的参考,也可以作为开发一个舞蹈相关网站的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值