T1 math:

  给定一个长度为n的数列以及模数k,判断对于任意n元组(x1,x2,...,xn)与该数列的标量积包含模数k同余类的多少项

对拓展欧基里德算法进行拓展可以得到:当且仅当gcd(a1,a2...an) | b 时 a1*x1+a2*x2+...+an*xn = b 有解

故求出数列各项与k的最大公约数,依次判断其是否整除(0,1...k-1)即可

代码如下:

NOIP 模拟十一_c++NOIP 模拟十一_git_02
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 #define C char
 5 const I MAXK = 1e6 + 5;
 6 I n,k,gcd,cnt,sta[MAXK];
 7 inline I read(){I x(0);C z(getchar());while(!isdigit(z))z=getchar();while(isdigit(z))x=x*10+(z^48),z=getchar();return x;}
 8 I GCD (I x,I y) {  return y == 0 ? x : GCD(y,x % y);  }
 9 signed main(){
10     n = read(),k = read(),gcd = read(), -- n;
11     while (n -- ) gcd = GCD(gcd,read());
12     gcd = GCD(gcd,k);
13     for (I i(0);i < k; ++ i) if (i % gcd == 0) sta[++cnt] = i;
14     printf("%d\n",cnt);
15     for (I i(1);i <= cnt; ++ i) printf("%d ",sta[i]);
16 }
View Code

 

T2 biology:

  给定n*m的矩阵,包含元素a,b 求一条以a为关键字严格递增的路径使得sigma(i,1,k){ b[i][j] } + sigma(i,1,k-1){ |Xi+1 - Xi| + |Yi+1 - Yi| }最大

考虑DP 定义dp(i,j)表示走到(i,j)路径的最大值,朴素做法显然是O(n^2*m^2)枚举进行转移

考虑优化枚举过程,常规思路为预处理或记忆化

首先保证dp转移的合理性,即预处理sort使得矩阵每个元素依据a严格递增

由于b[i][j]是常量,在预处理时直接赋值给dp即可,那么我们只需保证sigma(i,1,k-1){ |Xi+1 - Xi| + |Yi+1 - Yi| }最大

由于绝对值的不确定性使得其难以直接转移考虑将绝对值拆开进行转移

接下来考虑问题性质:最优问题,也就是说问题保证结果存在且最优

那么在dp进行过程中,直接记录上一阶段最优解(绝对值)进行转移即可

一种方法是直接记录拆开绝对值后各种情况(分类讨论)的最大值转移

另一种方法(思想相同),发现问题实际上是使曼哈顿距离最大,于是考虑转化为切比雪夫距离

这样在转移过程中只需要记录X或Y即可  ·

代码如下:

NOIP 模拟十一_c++NOIP 模拟十一_git_02
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 #define LL long long
 5 #define C char
 6 const I MAXN = 2e3 + 5;
 7 const I MAXM = 4e6 + 5;
 8 I n,m,a[MAXN][MAXN],b[MAXN][MAXN],tot,cnt,sta[MAXM];
 9 LL res,dp[MAXM];
10 struct Matrix {I x,y,a,b;} MAP[MAXM];
11 bool operator < (const Matrix &x,const Matrix &y) {  return x.a < y.a;  }
12 inline I read(){I x(0);C z(getchar());while(!isdigit(z))z=getchar();while(isdigit(z))x=x*10+(z^48),z=getchar();return x;}
13 signed main(){
14     n = read(),m = read();
15     for (I i(1);i <= n; ++ i)
16       for (I j(1);j <= m; ++ j) {
17         a[i][j] = read();
18         if (!a[i][j]) continue;
19         MAP[++tot].a = a[i][j],MAP[tot].x = i + j,MAP[tot].y = i - j;        
20       }
21     tot = 0;
22     for (I i(1);i <= n; ++ i)
23       for (I j(1);j <= m; ++ j) {
24         b[i][j] = read();
25         if (!a[i][j]) continue;
26         MAP[++tot].b = b[i][j];
27       }
28     sort (MAP + 1,MAP + tot + 1);
29     for (I i(1);i <= tot; ++ i) {
30         dp[i] = MAP[i].b;
31         if (MAP[i].a != MAP[i - 1].a) sta[++cnt] = i;
32     }
33     res = LONG_LONG_MIN,cnt = 2;
34     for (I i(1);i < sta[cnt]; ++ i) res = max (res,dp[i]);
35     LL max1(0),max2(0),max3(0),max4(0);
36     for (I i(sta[cnt]);i <= tot; ++ i) {
37         if (i == sta[cnt]) {
38           for (I j(sta[cnt - 1]);j < sta[cnt]; ++ j) {
39             max1 = dp[j] - MAP[j].x > max1 ? dp[j] - MAP[j].x : max1;
40             max2 = dp[j] + MAP[j].x > max2 ? dp[j] + MAP[j].x : max2;
41             max3 = dp[j] - MAP[j].y > max3 ? dp[j] - MAP[j].y : max3;
42             max4 = dp[j] + MAP[j].y > max4 ? dp[j] + MAP[j].y : max4;
43           }
44           cnt ++ ;
45         }
46         dp[i] += max(max(max1 + MAP[i].x,max2 - MAP[i].x),max(max3 + MAP[i].y,max4 - MAP[i].y));
47         res = dp[i] > res ? dp[i] : res;
48     }
49     printf("%lld",res);
50 }
View Code