review 9.29 viv 逃命 & 递归数列

T1

逃命

survive

Time Limit: 1 Sec  Memory Limit: 32768 K

Description

糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。

现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。

同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。

负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。

那么你就要安排大家的顺序。我们保证一定有解。

Input

第一行一个整数T(1 <= T <= 5),表示测试数据的个数。

然后对于每个测试数据,第一行有两个整数n(1 <= n <=
30000)和m(1 <= m <= 100000),分别表示人数和约束的个数。

然后m行,每行两个整数a和b,表示有一个约束a号必须在b号之前。a和b必然不同。

Output

对每个测试数据,输出一行排队的顺序,用空格隔开。

Sample Input

1

5 10

3 5

1 4

2 5

1 2

3 4

1 4

2 3

1 5

3 5

1 2

Sample Output

1 2 3 4 5

题目来源:LOI队内互水(nue) 版权所有:vivym

正解:

这个题显然是个变化过之后的图论。

这个题不知道为什么当时就想到了拓扑,没错,这个题真的是拓扑。

但是,这个题要求序号小的尽量靠前,很容易想到的方法是把每一个限制(a在b前面)建成一条a到b的边,然后进行拓扑,先出来的在前面。

但是,这样做是不正确的。

当时为什么我忘记了~~好像随便给了个2 1 3 的数据就卡死了~~

正解是反向建图,然后拓扑,这样就会倒序存在一个数组里面了,再倒序输出就好了。

下面是vivym的std

 1 #include <cstdio>
 2 #include <queue>
 3 #include <vector>
 4 #include <cstring>
 5 using namespace std;
 6
 7 const int maxn = 30000 + 5;
 8
 9 inline void scan(int &x)
10 {
11     char c; for(c = getchar();c < ‘0‘ || c > ‘9‘;c = getchar());    x = c - ‘0‘;
12     for(c = getchar();c >= ‘0‘ && c <= ‘9‘;c = getchar())   x = (x << 1) + (x << 3) + c - ‘0‘;
13 }
14
15 vector<int> G[maxn];
16 int deg[maxn],N,M,ans[maxn],an;
17
18 inline void solve()
19 {
20     priority_queue<int> Q;
21     for(int i = 1;i <= N;i ++)  if(!deg[i]) Q.push(i);
22     while(!Q.empty())
23     {
24         int u = Q.top();   Q.pop();
25         int sz = G[u].size();
26         for(int i = 0;i < sz;i ++)
27         {
28             int v = G[u][i];
29             if(-- deg[v] == 0)  Q.push(v);
30         }
31         ans[an ++] = u;
32     }
33 }
34
35 int main()
36 {
37     freopen("survive.in","r",stdin);    freopen("survive.out","w",stdout);
38     int T,u,v;  scan(T);
39     while(T --)
40     {
41         an = 0;
42         memset(deg,0,sizeof deg);
43         scan(N),scan(M);
44         for(int i = 1;i <= N;i ++)  G[i].clear();
45         while(M --) scan(u),scan(v),G[v].push_back(u),deg[u] ++;
46         solve();
47         for(int i = an - 1; i ;i --)    printf("%d ",ans[i]);
48         printf("%d\n",ans[0]);
49     }
50     return 0;
51 }
52 //by vivym

vivym

T2

递归数列

spp

Time Limit: 1 Sec  Memory Limit: 256 MB

Description

一个由自然数组成的数列按下式定义:

对于i <= k:ai
= bi

对于i > k: ai = c1ai-1
+ c2ai-2 + ... + ckai-k

其中bjcj1<=j<=k)是给定的自然数。写一个程序,给定自然数m <= n, 计算am + am+1 + am+2 + ... + an,
并输出它除以给定自然数p的余数的值。

Input

由四行组成。

第一行是一个自然数k

第二行包含k个自然数b1, b2,...,bk

第三行包含k个自然数c1, c2,...,ck

第四行包含三个自然数m, n, p

Output

仅包含一行:一个正整数,表示(am + am+1
+ am+2 + ... + an) mod p的值。

Sample Input

2
1 1
1 1
2 10 1000003

Sample Output

142

HINT

对于100%的测试数据:

1<= k<=15

1 <= m <= n <= 10^18

我不会,看std吧。

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4
 5 typedef long long LL;
 6 const int maxK = 15 + 2;
 7
 8 LL N,M,P;
 9
10 struct Mat
11 {
12     LL a[maxK][maxK],n;
13     Mat(int n,LL x = 0) : n(n)   { memset(a,0,sizeof(a));  for(int i = 0;i < n;i ++)   a[i][i] = x; }
14     inline Mat operator * (const Mat &b)    const
15     {
16         Mat c(n);
17         for(int i = 0;i < n;i ++)
18         for(int j = 0;j < n;j ++)
19         for(int k = 0;k < n;k ++)
20             (c.a[i][j] += (a[i][k] * b.a[k][j]) % P) %= P;
21         return c;
22     }
23 };
24
25 inline Mat pow(Mat a,LL b)
26 {
27     Mat c(a.n,1);
28     for(; b ;b >>= 1)
29     {
30         if(b & 1)   c = c * a;
31         a = a * a;
32     }
33     return c;
34 }
35
36 inline void scan(int &x)
37 {
38     char c; for(c = getchar();c < ‘0‘ || c > ‘9‘;c = getchar());    x = c - ‘0‘;
39     for(c = getchar();c >= ‘0‘ && c <= ‘9‘;c = getchar())   x = (x << 1) + (x << 3) + c - ‘0‘;
40 }
41
42 inline void scan(LL &x)
43 {
44     char c; for(c = getchar();c < ‘0‘ || c > ‘9‘;c = getchar());    x = c - ‘0‘;
45     for(c = getchar();c >= ‘0‘ && c <= ‘9‘;c = getchar())   x = (x << 1) + (x << 3) + c - ‘0‘;
46 }
47
48 int K;
49 LL B[maxK],C[maxK];
50
51 inline LL getans(LL p)
52 {
53     Mat x(K + 1);   LL sum = 0,ret = 0;
54     if(p <= K)
55     {
56         for(LL i = 0;i < p;i ++)   (ret += B[i]) %= P;
57         return ret;
58     }
59     x.a[0][0] = 1;
60     for(int i = 1;i <= K;i ++)  x.a[1][i] = x.a[0][i] = C[i - 1];
61     for(int i = 2;i <= K;i ++)  x.a[i][i - 1] = 1;
62     x = pow(x,p - K);
63     for(int i = 0;i < K;i ++)   (sum += B[i]) %= P;
64     ret = (x.a[0][0] * sum) % P;
65     for(int i = 1;i <= K;i ++)  (ret += x.a[0][i] * B[K - i] % P) %= P;
66     return ret;
67 }
68
69 int main()
70 {
71     freopen("spp.in","r",stdin);        freopen("spp.out","w",stdout);
72     scan(K);
73     for(int i = 0;i < K;i ++)   scan(B[i]);
74     for(int i = 0;i < K;i ++)   scan(C[i]);
75     scan(M);    scan(N);    scan(P);
76     for(int i = 0;i < K;i ++)   B[i] %= P,C[i] %= P;
77     printf("%lld",(getans(N) - getans(M - 1) + P) % P);
78     fclose(stdin);  fclose(stdout);
79     return 0;
80 }

vivym

时间: 2024-08-29 19:39:03

review 9.29 viv 逃命 & 递归数列的相关文章

【bzoj3231】[Sdoi2008]递归数列 矩阵乘法+快速幂

题目描述 一个由自然数组成的数列按下式定义: 对于i <= k:ai = bi 对于i > k: ai = c1ai-1 + c2ai-2 + ... + ckai-k 其中bj和 cj (1<=j<=k)是给定的自然数.写一个程序,给定自然数m <= n, 计算am + am+1 + am+2 + ... + an, 并输出它除以给定自然数p的余数的值. 输入 由四行组成. 第一行是一个自然数k. 第二行包含k个自然数b1, b2,...,bk. 第三行包含k个自然数c1,

【SDOI2008】【BZOJ3231】递归数列

Description 一个由自然数组成的数列按下式定义: 对于i <= k:ai = bi 对于i > k: ai = c1ai-1 + c2ai-2 + - + ckai-k 其中bj和 cj (1<=j<=k)是给定的自然数.写一个程序,给定自然数m <= n, 计算am + am+1 + am+2 + - + an, 并输出它除以给定自然数p的余数的值. Input 由四行组成. 第一行是一个自然数k. 第二行包含k个自然数b1, b2,-,bk. 第三行包含k个自然

[luogu2461 SDOI2008] 递归数列 (矩阵乘法)

传送门 Description 一个由自然数组成的数列按下式定义: 对于i <= k:ai = bi 对于i > k: ai = c1ai-1 + c2ai-2 + ... + ckai-k 其中bj 和 cj (1<=j<=k)是给定的自然数.写一个程序,给定自然数m <= n, 计算am + am+1 + am+2 + ... + an, 并输出它除以给定自然数p的余数的值. Input 输入文件spp.in由四行组成. 第一行是一个自然数k. 第二行包含k个自然数b1,

证明一个递归数列极限的存在

If ${x_{n + 1}} = \cos {x_n}$, prove that $\mathop {\lim }\limits_{n \to \infty } {x_n}$ exists. Note 1: As we want to prove that a limit of sequence exist, some methods can be used. $\left\{ {{x_n}} \right\}$ is bounded and monotonic, then $\left\{

bzoj 3231: [Sdoi2008]递归数列【矩阵乘法】

今天真是莫名石乐志 一眼矩阵乘法,但是这个矩阵的建立还是挺有意思的,就是把sum再开一列,建成大概这样 然后记!得!开!long!long!! #include<iostream> #include<cstdio> using namespace std; const int N=20; long long n,b[N],c[N],sum,l,r,mod; struct jz { long long a[N][N]; jz operator * (const jz &b)

[SDOI2008]递归数列

嘟嘟嘟 裸的矩阵快速幂,构造一个\((k + 1) * (k + 1)\)的矩阵,把sum[n]也放到矩阵里面就行了. #include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<cctype> #include<vector> #incl

洛谷 P1181,1182 数列分段Section

数列分段Section I 题目描述 对于给定的一个长度为N的正整数数列A[i],现要将其分成连续的若干段,并且每段和不超过M(可以等于M),问最少能将其分成多少段使得满足要求. 输入输出格式 输入格式: 输入文件divide_a.in的第1行包含两个正整数N,M,表示了数列A[i]的长度与每段和的最大值,第2行包含N个空格隔开的非负整数A[i],如题目所述. 输出格式: 输出文件divide_a.out仅包含一个正整数,输出最少划分的段数. 输入输出样例 输入样例#1: 5 6 4 2 4 5

常见的五类排序算法图解和实现(交换类:冒泡排序,递归的快速排序)

冒泡排序算法: 总的来说就是两两交换,反复直到有序,第一个记录和第二个记录,若逆序则交换,然后比较第二个和第三个记录,以此类推,直到第 n 个记录和第 n-1个记录比较完毕为止,第一趟排序,结果关键字最大的记录被安排在最后一个位置.对前 n-1个记录继续冒泡排序,使得关键字次大的记录安排在第 n-1个位置.如此重复,直到没有需要交换的记录为止(仅仅是第一个和第二个交换过为止).整个一趟趟的选出最值的过程,仿佛是那水里的气泡,咕嘟咕嘟的往上翻的过程. 递增冒泡排序过程图解: 一般先比较第一个元素和

dom4j递归解析XML字符串所有子节点

1 /** 2 * dom4j递归解析所有子节点 3 * 4 * @param childElements 5 * @param mapEle 6 * @return 7 */ 8 public Map<String, Object> getElementsToString(String print) { 9 //解析返回的xml字符串,生成document对象 10 Document document = null; 11 Map<String,Object> mapEle =