A:水题,模拟。

#include <bits/stdc++.h>
using namespace std;
int a[100][100];
int n;
bool check(int r, int c){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            if(a[r][i]+a[j][c]==a[r][c]) return 1;
        }
    }
    return 0;
}
int main()
{
    bool flag=1;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            scanf("%d",&a[i][j]);
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            if(a[i][j]==1) continue;
            if(check(i,j)==0) flag=0;
        }
    }
    if(flag) puts("Yes");
    else puts("No");
}

B,枚举每一个纵坐标的可能点,根据直线表达式算出对应的x,只要统计出当前(x,y)和坐标轴的矩形的答案,去和全局维护的最优答案比较即可。我们发现计算x,y下方所有的点的横纵坐标之和可以利用两次等差数列来算,这个就很简单了。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL m, b, x, y;
int main()
{
    scanf("%lld%lld",&m,&b);
    LL ans1=0,ans=0;
    for(int y=0; y<=b; y++)
    {
        x = (b-y)*m;
        ans1=0;
        ans1+=(x+1)*(y+1)*y/2;
        ans1+=x*(y+1+(y+1)*x)/2;
        ans=max(ans,ans1);
    }

    printf("%lld\n", ans);
    return 0;
}

C,题意就是有两个操作,add就是往栈里push一个数,remove就是移除栈顶元素。现在要求数字按照1-n的顺序移除。问至少需要改动多少次,改动的意思就是把当前栈里面的元素排序。 解法:直接用vector模拟这个过程,add就直接add,remove的时候要是不满足就直接清空vector。

#include <bits/stdc++.h>
using namespace std;
vector <int> v;
char s[10];
int n, x;
int main()
{
    scanf("%d", &n);
    int cnt = 1, ans = 0;
    for(int i=1; i<=n*2; i++){
        scanf("%s", s);
        if(s[0]=='a'){
            scanf("%d", &x);
            v.push_back(x);
        }
        else{
            if(v.empty());
            else if(v.back()==cnt) v.pop_back();
            else{
                ans++,v.clear();
            }
            cnt++;
        }
    }
    printf("%d\n", ans);
    return 0;
}

D,有个n*m的矩形上面有k盏灯,没盏灯占了一个格子。只能走有灯的格子,但是当在一个原始就有灯的地方可以花费1使得一行或者一列变亮,现在要求你从左上角(1,1)走到右下角(n,m),求最小花费。

题解:首先把题目上的k个点当成图中的点,由于站在一个初始亮的点可以点亮一行一列,所以我们可以在这个点上,点亮相邻的一行或者一列。所以想到一个图论比较常见的套路,引入行列作为图中的点,然后以k个点,外加k个行形成的点,k个列形成的点来建图。从1个点到相邻行列的花费是1,反向花费是0。还有图本身就有的边,以及为了便于处理在(n,m)没有灯的情况下增加1个k+1这个点表示(n,m),然后跑一遍最短路算法。

这里写代码片
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000000;
const int inf = 0x3f3f3f3f;
struct edge{
    int to, w, next;
    edge(){}
    edge(int to, int w, int next):to(to),w(w),next(next){}
}E[maxn*2];
int head[maxn], edgecnt, dis[maxn];
void init(){
    memset(head,-1,sizeof(head));
    edgecnt=0;
}
void add(int u, int v, int w){
    E[edgecnt].to=v,E[edgecnt].w=w,E[edgecnt].next=head[u],head[u]=edgecnt++;
}
int dir[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
pair<int, int> p[maxn];
map <pair<int, int>, int> mp;
bool vis[maxn];
int n, m, k;
void Dij(int s){
    priority_queue<pair<int,int>,vector<pair<int,int> >, greater<pair<int,int> > >q;
    for(int i = 0; i < maxn; i++) dis[i] = inf;
    memset(vis, 0, sizeof(vis));
    dis[s]=0;
    q.push(make_pair(0,s));
    while(!q.empty()){
        pair<int,int> p = q.top(); q.pop();
        int u = p.second;
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = head[u]; ~i; i=E[i].next){
            int v = E[i].to, w = E[i].w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                q.push(make_pair(dis[v], v));
            }
        }
    }
}
int main()
{
    init();
    scanf("%d %d %d", &n,&m,&k);
    int bas = 1e4+7;
    for(int i=1; i<=k; i++){
        int r, c;
        scanf("%d %d", &r,&c);
        add(i,r+bas,1);
        add(i,c+2*bas,1);
        add(i,r+bas+1,1);
        add(i,c+2*bas+1,1);
        add(i,r+bas-1,1);
        add(i,c+2*bas-1,1);

        add(r+bas,i,0);
        add(c+2*bas,i,0);
        add(r+bas+1,i,0);
        add(c+2*bas+1,i,0);
        add(r+bas-1,i,0);
        add(c+2*bas-1,i,0);
        p[i] = {r, c};
        mp[make_pair(r,c)] = i;
    }
    for(int i=1; i<=k; i++){
        for(int j=0; j<4; j++){
            int x = p[i].first+dir[j][0];
            int y = p[i].second+dir[j][1];
            if(mp.find(make_pair(x,y))!=mp.end()){
                add(i,mp[make_pair(x,y)],0);
            }
        }
    }
    if(mp.find(make_pair(n,m))==mp.end()){
        add(n+bas,k+1,0);
        add(m+2*bas,k+1,0);
    }
    Dij(mp[make_pair(1,1)]);
    int ans;
    if(mp.find(make_pair(n,m))==mp.end()){
        ans = dis[k+1];
    }
    else{
        ans = dis[mp[make_pair(n,m)]];
    }
    if(ans == inf) ans = -1;
    printf("%d\n", ans);
    return 0;
}

E,
我们现在位于(0,0)处,目标是走到(K,0)处。
每一次我们都可以从(x,y)走到(x+1,y-1)或者(x+1,y)或者(x+1,y+1)三个位子之一。
现在一共有N段线段,每条线段都是平行于X轴的。
我们如果此时x是在这段线段之内的话,我们此时走到的点(x,y)需要满足0<=y<=Ci.
现在保证一段线段的终点,一定是下一段线段的起点。
问我们从起点走到终点的行走方案数。

解法:比赛的时候看到很多人在群里说这个题就是分段的矩阵快速幂,很简单。只能感叹这个世界太强,我快要go die了。首先考虑一下线段只有一条并且k很小,那么可以想到一个朴素的递推。dp[i][j]表示走到(i,j)的方案数。那么有

dp[i][j]=dp[i1][j]+dp[i1][j1]+dp[i1][j+1]

初始化dp[0][0] = 1

但是这里k很大,那么我们利用矩阵快速幂对每一段的状态转移过程快速幂优化即可。注意到ci<=15。我们可以这样构造这个转移矩阵

dp[1]dp[2]dp[3]...dp[15]

×

110000000000000111000000000000011100000000000...000000000000011

dpnxt[1]dpnxt[2]dpnxt[3]...dpnxt[15]

这个过程维护到达上一次线段终点的可行方案数,然后继续转移下一条线段,知道最后为止。

参考博客:http://blog.csdn.net/mengxiang000000/article/details/73740695

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
///分段矩阵快速幂
const LL mod = 1e9+7;
struct Matrix{
    LL maze[17][17];
    void init(){
        memset(maze,0,sizeof(maze));
    }
};
Matrix A,B,pre;
Matrix mul(Matrix a, Matrix b, LL len){
    Matrix res;
    res.init();
    for(int i=0; i<=len; i++)
        for(int j=0; j<=len; j++)
            for(int k=0; k<=len; k++)
                res.maze[i][j] = (res.maze[i][j]+(a.maze[i][k]%mod*b.maze[k][j]%mod)%mod)%mod;
    return res;
}
Matrix ksm(Matrix a, LL n, LL len){
    Matrix res;
    res.init();
    for(int i=0; i<=len; i++){
        res.maze[i][i]=1;
    }
    while(n){
        if(n&1) res = mul(res, a, len);
        a = mul(a, a, len);
        n >>= 1;
    }
    return res;
}

int main()
{
    LL n, en;
    scanf("%lld%lld", &n, &en);
    pre.init();
    A.init();
    for(int i=0; i<16; i++){
        for(int j=i-1; j<i+2&&j<16; j++){
            if(j>=0&&j<=15){
                A.maze[i][j]=1;
            }
        }
    }
    bool ok = 0;
    pre.maze[0][0] = 1;
    for(int i=1; i<=n; i++){
        LL L, R, y;
        scanf("%lld %lld %lld", &L, &R, &y);
        if(R > en) R = en, ok = 1;
        B = ksm(A, R-L, y);
        for(LL j=y+1; j<=15; j++) pre.maze[j][0]=0;
        B = mul(B, pre, y);
        for(int j=0; j<=y; j++){
            pre.maze[j][0] = B.maze[j][0];
        }
        if(ok) break;
    }
    printf("%lld\n", B.maze[0][0]);
    return 0;
}