zoukankan      html  css  js  c++  java
  • 发个题目坑 二模03day1

    1.数列(seq2.pas/c/cpp)

    题目描述

    一个数列定义如下:f(1) = 1,f(2) = 1,f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7。给定 A,B 和 n 的值,要求计算 f(n)的值。

    输入格式

    仅一行包含 3 个整数 A,B 和 n,其中(1≤ A, B ≤1000, 1 ≤n≤100,000,000)。

    输出格式

    仅一行,一个整数,即 f(n)的值。

    输入输出样例

    input:                 |  output:
    -----------------------------------
    1 1 3 | 2
    -----------------------------------
    1 2 10 | 5

    分析

    这是一道比较有意思的题目,虽然比较水,AC算法也不是每人都能想到的啦啦啦.
    首先看到输出的数据范围,非常小对不对!$0le f(n)le 6$.然后研究这个递推数列的性质.它是一个线性递推数列,也就是可以用矩阵快速幂做.但是这样还是太麻烦了呢.
    注意到这个数列像极了Fibonacci数列,嗯,让我们称它为"Coefficient Extended Fibonacci Sequence of Natural Numbers",附个简称叫CEFSNN.虽然这没什么用啊...也是装逼利器对不~
    把求f(n)的表达式换一个写法会怎么样呢?
    f(n)=((A*f(n-1))mod 7+(B*f(n-2))mod 7)mod 7
    然后A,B都是常量嗯.
    那么因为 A*f(n-1)mod 7=(A mod 7)*(f(n-1)mod 7)mod 7 嗯,B...同理
    A mod 7 也是常量吖.
    那么设两个数$x,y in mathbb{N}$,只要$f(x)equiv f(y) pmod{7}$且$f(x+1)equiv f(y+1) pmod{7}$则x与y之间就是一个循环节.
    因为前后两个数排列最多49种,寻找循环节长度不会超过49.(如果超过根据鸽笼原理可知肯定有一个更小的循环节,且有一个显然的结论即是若a和b都可作为循环节长度,则gcd(a,b)也可以.扯远了)
    这题正解应该就是这个了.
    当然有兴趣试试Matrix Multiplication哈.

    代码

    因为逗逼的po主是先写题解再写题目的所以...(不拿代码讲算法都是耍流氓!!)哎别打我!!我写个不成吗? 
    #include "cstdio"
    int a,b,n,i,p,f[60];
    bool h[80];
    int main(){
    	freopen("seq2.in","r",stdin);
    	freopen("seq2.out","w",stdout);
    	scanf("%d%d%d",&a,&b,&n);
    	a%=7;
    	b%=7;
    	f[1]=f[2]=1;
    	h[9]=true;
    	for(i=3;i<52;++i){
    		f[i]=(a*f[i-1]+b*f[i-2])%7;
    		if(n==i){
    			printf("%d
    ",f[i]);
    			return 0;
    		}
    		if(h[f[i]*8+f[i-1]]){
    			p=i-2;
    			break;
    		}else{
    			h[f[i]*8+f[i-1]]=true;
    		}
    	}
    	printf("%d
    ", f[(n-1)%p+1]);
    	return 0;
    }

    2.最长路(path.pas/c/cpp)

    题目描述

    设 G 为有 n 个顶点的有向无环图,G 中各顶点的编号为 1 到 n,且当<i,j>为 G 中的一条边时有i < j。设 w(i,j)为边<i,j>的长度,请设计算法,计算图 G 中<1,n>间的最长路径。

    输入数据

    第一行有两个整数 n 和 m,表示有 n 个顶点和 m 条边,其中(2≤n≤1500,m≤50000),接下来 m 行中每行输入 3 个整数 a ,b,v 表示从 a 点到 b 点有条边,边的长度为 v。

    输出数据

    一个整数,即 1 到 n 之间的最长路径.如果 1 到 n 之间没连通,输出-1。

    输入输出样例

    input:                 |  output:
    -----------------------------------
    2 1 |
    1 2 1 | 2

    题解

    良心傻逼题.因为是有向无环图,SFPA大胆做.注意判断连通性和是求最长路.

    代码

    话说这是一次通过的节奏?但要是我连SPFA都写错我还怎么有脸混OI界?(果然错了呜呜呜呜~~~)
    #include <cstdio>
    int next[70000],to[70000],hl,head[3000],le[70000];
    inline void addEdge(int f,int t,int v){
    	++hl;
    	next[hl]=head[f];
    	to[hl]=t;
    	le[hl]=v;
    	head[f]=hl;
    }
    int i,j,k,l,a,b,c,m,n;
    int qh,qt,q[600000],f[3000];
    bool iq[3000],vis[3000];
    void spfa(){
    	vis[1]=iq[1]=true;
    	qt=2;
    	qh=1;
    	q[1]=1;
    	while(qh!=qt){
    		i=q[qh];
    		iq[i]=false;
    		for(j=head[i];j!=0;j=next[j]){
    			vis[k=to[j]]=true;
    			l=le[j];
    			if(f[i]+l>f[k]){
    				f[k]=f[i]+l;
    				if(!iq[k]){
    					iq[k]=true;
    					q[qt++]=k;
    				}
    			}
    		}
    		++qh;
    	}
    }
    int main(int argc, char const *argv[]){
    	freopen("path.in","r",stdin);
    	freopen("path.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for(i=0;i<m;++i){
    		scanf("%d%d%d",&a,&b,&c);
    		addEdge(a,b,c);
    	}
    	spfa();
    	if(!vis[n]){
    		printf("-1
    ");
    	}else{
    		printf("%d
    ", f[n]);
    	}
    	return 0;
    }

    3. 翻转游戏(flip.pas/c/cpp)

    题目描述

    翻转游戏是在一个 4 格×4 格的长方形上进行的,在长方形的 16 个格上每个格子都放着一个双面的物件。每个物件的两个面,一面是白色,另一面是黑色,每个物件要么白色朝上,要么黑色朝上,每一轮你只能翻 3 至 5 个物件,从而由黑到白的改变这些物件上面的颜色,反之亦然。每一轮被选择翻转的物件遵循以下规则:
    1、从 16 个物件中任选一个。
    2、翻转所选择的物件的同时,所有与它相邻的左方物件、右方物件、上方物件和下方物件(如果有的话),都要跟着翻转。以下为例:
     bwbw
     wwww
     bbwb
     bwwb
    这里"b"表示该格子放的物件黑色面朝上、"w"表示该格子放的物件白色朝上。如果我们选择翻转 第三行的第一个物件(如图所示),那么格子状态将变为:
     bwbw
     bwww
     wwwb
     wwwb
    游戏的目标是翻转到所有的物件白色朝上或黑色朝上。你的任务就是写一个程序来求最少的翻转 次数来实现这一目标。

    输入格式

    包含 4 行,每行 4 个字符,每个字符"w" 或 "b"表示游戏开始时格子上物件的状态。

    输出格式

    仅一个整数,即从给定状态到实现这一任务的最少翻转次数。如果给定的状态就已经实现了目标 就输出 0,如果不可能实现目标就输出"Impossible"。

    输入输出样例

    input:          | output:
    -------------------------
    bwwb |
    bbwb | 4
    bwwb |
    bwww |

    题解

    压位+BFS.
    将这个长方形的每一个格子都用二进制保存,这个数可以保存到一个int类型里;然后用位运算xor一个数表示一次翻转,BFS类似于SPFA搜索即可.
    其实很快的.

    代码

    #include "cstdio"
    #include <cstring>
    #define min(a,b) ((a)<(b)?(a):(b))
    const int op[16]={19, 39, 78, 140, 305, 626, 1252, 2248, 4880, 10016, 20032, 35968, 12544, 29184, 58368, 51200};
    int q[600000],qh,qt;
    bool iq[80000],ok;
    int i,j,k,s,f[80000],mi;
    char p[10];
    int main(){
    	freopen("flip.in","r",stdin);
    	freopen("flip.out","w",stdout);
    	k=1;
    	for(i=0;i<4;++i){
    		scanf("%s
    ",p);
    		for(j=0;j<4;++j){
    			s|=(p[j]=='b'?k:0);
    			k<<=1;
    		}
    	}
    	memset(f,1,sizeof f);
    	q[0]=s;
    	f[s]=0;
    	qt=1;
    	mi=0x7fffffff;
    	if(s==65535||!s){
    		printf("0
    ");
    		return 0;
    	}
    	while(qh!=qt){
    		i=q[qh];
    		iq[i]=false;
    		if(f[i]>=mi-1){
    			++qh;
    			continue;
    		}
    		for(j=0;j<16;++j){
    			k=i^op[j];
    			if(f[k]>f[i]+1){
    				f[k]=f[i]+1;
    				if(k==65535||!k){
    					ok=true;
    					mi=f[k];
    				}
    				if(!iq[k]){
    					iq[k]=true;
    					q[qt++]=k;
    				}
    			}
    		}
    		++qh;
    	}
    	if(ok){
    		printf("%d
    ", mi);
    	}else{
    		printf("Impossible
    ");
    	}
    	return 0;
    }//妈旦说好的TG组难度呢?上次还考平衡树来着...
  • 相关阅读:
    深度解析正则表达式exec和match两者使用的异同以及要注意的地方
    CSS中有关水平居中和垂直居中的解决办法
    Ubunut16.04 安装 Mahout
    正则表达式常用方法
    python字符串判断
    python list
    python一些包
    数据科学中的R和Python: 30个免费数据资源网站
    simple vimrc for python
    python的一些方法
  • 原文地址:https://www.cnblogs.com/tmzbot/p/3971394.html
Copyright © 2011-2022 走看看