CSP-S模拟15

不甘失败其实是个伪命题——如果我还未竭尽全力,那我应该毫无怨言;如果我已经竭尽全力,那我应该愿赌服输。

 

A. 网格图

暴力做法1:每次更新图,来一个bfs。

code
//正青春的年华,就是应该献给直指星辰的梦想啊!
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 502;
const ll mod = 1e9 + 7;

int ans, res, c[maxn][maxn], d[maxn][maxn], n, k;
char s[maxn];
queue<pair<int, int> > q;
bool vis[maxn][maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}

void bfs(int x, int y)
{
    q.push(make_pair(x, y));
    while(!q.empty())
    {
        int n1 = q.front().first, n2 = q.front().second; q.pop();
        if(vis[n1][n2]) continue;
        vis[n1][n2] = 1; res++;
        if(n1+1<=n && !vis[n1+1][n2] && d[n1+1][n2]==0) q.push(make_pair(n1+1, n2));
        if(n2+1<=n && !vis[n1][n2+1] && d[n1][n2+1]==0) q.push(make_pair(n1, n2+1));
        if(n1-1>=1 && !vis[n1-1][n2] && d[n1-1][n2]==0) q.push(make_pair(n1-1, n2));
        if(n2-1>=1 && !vis[n1][n2-1] && d[n1][n2-1]==0) q.push(make_pair(n1, n2-1));
    }
}

void change(int x, int y)
{
    memcpy(d, c, sizeof(c));
    for(int i=x; i<=x+k-1; i++)
    {
        for(int j=y; j<=y+k-1; j++)
        {
            d[i][j] = 0;
        }
    }
    /*printf("New Change %d %d\n", x, y);
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++) printf("%d ", d[i][j]);
        printf("\n");
    }
    printf("\n");*/
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++) vis[i][j] = 0;
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(d[i][j]==0 && !vis[i][j])
            {
                res = 0; bfs(i, j);
                //printf("begin from: %d %d\n", i, j);
                //printf("res = %d\n", res);
                if(res > ans) ans = res;
            }
        }
    }
}

int main()
{
    n = read(); k = read();
    for(int i=1; i<=n; i++)
    {
        scanf("%s", s+1);
        for(int j=1; j<=n; j++)
        {
            if(s[j] == '.') c[i][j] = 0;
            else c[i][j] = 1;
        }
    }
    /*printf("Before Change:\n");
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++) printf("%d ", c[i][j]);
        printf("\n");
    }
    printf("\n");*/
    for(int i=1; i<=n-k+1; i++)
    {
        for(int j=1; j<=n-k+1; j++)
        {
            change(i, j);
        }
    }
    printf("%d\n", ans);
    
    return 0;
}

暴力做法2:预处理连通快并涂色,直接循环i, j找到和k*k的正方形相交(包括内部)的所有联通块,减去k*k内1的个数,再加上k*k。(以上都是50分)

code
//正青春的年华,就是应该献给直指星辰的梦想啊!
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 502;
const ll mod = 1e9 + 7;

int ans, res, c[maxn][maxn], n, k, bel[maxn][maxn], val[maxn*maxn], col;
char s[maxn];
queue<pair<int, int> > q;
bool vis[maxn][maxn], ext[maxn*maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}

void bfs(int x, int y, int col)
{
    q.push(make_pair(x, y));
    while(!q.empty())
    {
        int n1 = q.front().first, n2 = q.front().second; q.pop();
        if(vis[n1][n2]) continue;
        vis[n1][n2] = 1; res++;
        bel[n1][n2] = col;
        if(n1+1<=n && !vis[n1+1][n2] && c[n1+1][n2]==0) q.push(make_pair(n1+1, n2));
        if(n2+1<=n && !vis[n1][n2+1] && c[n1][n2+1]==0) q.push(make_pair(n1, n2+1));
        if(n1-1>=1 && !vis[n1-1][n2] && c[n1-1][n2]==0) q.push(make_pair(n1-1, n2));
        if(n2-1>=1 && !vis[n1][n2-1] && c[n1][n2-1]==0) q.push(make_pair(n1, n2-1));
    }
}

void change(int x, int y)
{
    //printf("From: %d %d\n", x, y);
    int sum = 0;
    for(int i=1; i<=col; i++) ext[i] = 0;
    for(int i=x; i<=x+k-1; i++)
    {
        for(int j=y; j<=y+k-1; j++)
        {
            if(!ext[bel[i][j]]) 
            {
                sum += val[bel[i][j]], ext[bel[i][j]] = 1;
                //printf("col %d is in\n", bel[i][j]);
                //printf("upd: %d\n", val[bel[i][j]]);
            }
            if(c[i][j] == 0) sum--;
        }
    }
    if(x-1>=1)
    {
        for(int j=y; j<=y+k-1; j++)
        {
            if(!ext[bel[x-1][j]])
            {
                sum += val[bel[x-1][j]], ext[bel[x-1][j]] = 1;
                //printf("col %d is in\n", bel[x-1][j]);
                //printf("upd: %d\n", val[bel[x-1][j]]);
            }
        }
    }
    if(x+k<=n)
    {
        for(int j=y; j<=y+k-1; j++)
        {
            if(!ext[bel[x+k][j]])
            {
                sum += val[bel[x+k][j]], ext[bel[x+k][j]] = 1;
                //printf("col %d is in\n", bel[x+k][j]);
                //printf("upd: %d\n", val[bel[x+k][j]]);
            }
        }
    }
    if(y-1>=1)
    {
        for(int i=x; i<=x+k-1; i++)
        {
            if(!ext[bel[i][y-1]])
            {
                sum += val[bel[i][y-1]], ext[bel[i][y-1]] = 1;
                //printf("col %d is in\n", bel[i][y-1]);
                //printf("upd: %d\n", val[bel[i][y-1]]);
            }
        }
    }
    if(y+k<=n)
    {
        for(int i=x; i<=x+k-1; i++)
        {
            if(!ext[bel[i][y+k]])
            {
                sum += val[bel[i][y+k]], ext[bel[i][y+k]] = 1;
                //printf("col %d is in\n", bel[i][y+k]);
                //printf("upd: %d\n", val[bel[i][y+k]]);
            }
        }
    }
    sum += k * k;
    //printf("sum = %d\n", sum);
    if(sum == 13) exit(0);
    if(sum > ans) ans = sum;
}

int main()
{
    //freopen("grid2.in", "r", stdin);
    
    n = read(); k = read();
    for(int i=1; i<=n; i++)
    {
        scanf("%s", s+1);
        for(int j=1; j<=n; j++)
        {
            if(s[j] == '.') c[i][j] = 0;
            else c[i][j] = 1;
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(!vis[i][j] && c[i][j] == 0) 
            {
                col++; res = 0;
                bfs(i, j, col); val[col] = res;
            }
        }
    }
    /*for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            printf("%d ", bel[i][j]);
        }
        printf("\n");
    }
    for(int i=1; i<=col; i++) printf("val[%d] = %d\n", i, val[i]);*/
    for(int i=1; i<=n-k+1; i++)
    {
        for(int j=1; j<=n-k+1; j++)
        {
            change(i, j);
        }
    }
    printf("%d\n", ans);
    
    return 0;
}

正解的做法和莫队真的像极了,从排序到add和del再到“奇偶性优化”,所以上一次计算的东西依然有效,每次只修改一部分就行了。

code
//正青春的年华,就是应该献给直指星辰的梦想啊!
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 502;
const int N = 250010;
const ll mod = 1e9 + 7;

int n, k, sum1, sum2, up, dn, lt, rt, ans, tot;
int id[maxn][maxn], sz[N], q[N][2], l, r, ck[N];
bool vis[maxn][maxn];
int bh[5] = {0, -1, 1, 0, 0};
int bl[5] = {0, 0, 0, -1, 1};
char s[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}

inline void bfs(int xx, int yy)
{
    l = 1, r = 0;
    q[++r][0] = xx; q[r][1] = yy;
    id[xx][yy] = ++tot; sz[tot] = 1;
    int hg, le, x, y;
    while(l <= r)
    {
        x = q[l][0], y = q[l][1];
        l++;
        for(int i=1; i<=4; i++)
        {
            hg = x + bh[i], le = y + bl[i];
            if(hg <= 0 || le <= 0 || hg > n || le > n) continue;
            if(vis[hg][le] && !id[hg][le])
            {
                id[hg][le] = tot; 
                q[++r][0] = hg; q[r][1] = le;
                sz[tot]++;
            }
        }
    }
}

inline void del(int x, int y)
{
    ck[id[x][y]]--;
    sum2--;
    if(!ck[id[x][y]]) sum1 -= sz[id[x][y]];
}
inline void add(int x, int y)
{
    if(!ck[id[x][y]]) sum1 += sz[id[x][y]];
    ck[id[x][y]]++;
    sum2++;
}
inline void pre()
{
    for(int i=1; i<=k; i++)
    {
        for(int j=1; j<=k; j++) if(vis[i][j]) add(i, j);
    }
    for(int i=1; i<=k; i++)
    {
        if(vis[k+1][i]) add(k+1, i), dn++;
    }
    for(int i=1; i<=k; i++)
    {
        if(vis[i][k+1]) add(i, k+1), rt++;
    }
    ans = max(ans, sum1+k*k-sum2+dn+rt);
}

inline void workr(int x, int y)
{
    int xx = x-k+1, yy = y-k+1;
    if(xx > 1)
    {
        if(vis[xx-1][yy]) del(xx-1, yy), up--;
        if(vis[xx-1][y+1]) add(xx-1, y+1), up++;
    }
    if(x < n)
    {
        if(vis[x+1][yy]) del(x+1, yy), dn--;
        if(vis[x+1][y+1]) add(x+1, y+1), dn++;
    }
    lt = rt = 0;
    for(int i=xx; i<=x; i++)
    {
        if(yy > 1 && vis[i][yy-1]) del(i, yy-1);
        if(vis[i][yy]) lt++;
        if(y <= n-2 && vis[i][y+2]) add(i, y+2), rt++;
    }
    ans = max(ans, sum1+k*k-sum2+up+dn+lt+rt);
}

inline void workl(int x, int y)
{
    int xx = x-k+1, yy = y-k+1;
    if(xx > 1)
    {
        if(vis[xx-1][y]) del(xx-1, y), up--;
        if(vis[xx-1][yy-1]) add(xx-1, yy-1), up++;
    }
    if(x < n)
    {
        if(vis[x+1][y]) del(x+1, y), dn--;
        if(vis[x+1][yy-1]) add(x+1, yy-1), dn++;
    }
    lt = rt = 0;
    for(int i=xx; i<=x; i++)
    {
        if(y < n && vis[i][y+1]) del(i, y+1);
        if(vis[i][y]) rt++;
        if(yy >= 3 && vis[i][yy-2]) add(i, yy-2), lt++;
    }
    ans = max(ans, sum1+k*k-sum2+up+dn+lt+rt);
}

inline void workd(int x, int y)
{
    int xx = x-k+1, yy = y-k+1;
    if(yy > 1)
    {
        if(vis[xx][yy-1]) del(xx, yy-1), lt--;
        if(vis[x+1][yy-1]) add(x+1, yy-1), lt++;
    }
    if(y < n)
    {
        if(vis[xx][y+1]) del(xx, y+1), rt--;
        if(vis[x+1][y+1]) add(x+1, y+1), rt++;
    }
    up = dn = 0;
    for(int i=yy; i<=y; i++)
    {
        if(xx > 1 && vis[xx-1][i]) del(xx-1, i);
        if(vis[xx][i]) up++;
        if(x <= n-2 && vis[x+2][i]) add(x+2, i), dn++;
    }
    ans = max(ans, sum1+k*k-sum2+up+dn+lt+rt);
}

int main()
{
    n = read(); k = read();
    for(int i=1; i<=n; i++)
    {
        scanf("%s", s+1);
        for(int j=1; j<=n; j++)
        {
            if(s[j] == '.') vis[i][j] = 1;
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(vis[i][j] && !id[i][j]) bfs(i, j);
        }
    }
    pre();
    for(int i=k; i<=n; i++)
    {
        if((i-k+1)&1)
        {
            for(int j=k; j<n; j++) workr(i, j);
            if(i < n) workd(i, n);
        }
        else 
        {
            for(int j=n; j>k; j--) workl(i, j);
            if(i < n) workd(i, k);
        }
    }
    printf("%d\n", ans);
    
    return 0;
}

 

B. 保险箱

有两个重要结论:1.若x是密码,gcd(x, n)也是密码,(直接输出n / gcd(x, n)可得34 pts)。

证明:学习同余方程时学到 a *x + b * y = gcd(x, y) 一定有解,设x是密码,所以x * k - n * c = gcd(x, n) 一定有解,所以x * k % n = gcd(x, n) 一定有解,由题意得 x * k % n 是密码,所以 gcd(x, n) 也是密码。

2.若x, y是密码,gcd(x, y)也是密码。

证明:设 x, y 是密码,那么 (p * x + q * y) % n 也是密码(p, q是任意正整数),因为a * x + b * y = gcd(x, y)一定有解,所以 a * x + b * y 和 gcd(x, y) 在 mod n 意义下同余一定有解。

因为 a * x + b * y 和 a * x + b * y + p * n + x + q * n * x 在 mod n 意义下同余,右边合并为 (a + p * n) * x + (b + q * n),它和 gcd(x, y) (mod n) 同余 一定有解,因为它是密码,所以 gcd(x, y) 也是密码。

设密码集合为A,A中所有数求 gcd 的结果为 x,所以A中所有数都是x的倍数,并且一定是连取的x, 2 * x, 3 * x……由结论2的 x 属于 A,而且是A中最小的数。反证法因为如果集合A中存在 y < x,那么gcd(x, y) < x,与假设不相符。

目的是让A最大化,所以要找到一个最小的x。m[k]一定在集合里,由1得 gcd(m[k], n) 一定在集合里,它一定是x的倍数,这可以初步确定x的范围。取gcd是为了取尽量小的范围。对于1 <= i < k,m[i]一定不在集合里,所以它一定不是x 的倍数,所以我们从 gcd(m[k], n) 的因数中删掉同时是 m[i] (1 <= i < k) 的数就好了。

因为只要找最小值,可以先判断可能更优再check,先把m排个序可以及时返回合法方案。

code
//正青春的年华,就是应该献给直指星辰的梦想啊!
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 250005;

ll n, k, m[maxn];

inline ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}

ll gcd(ll a, ll b)
{
    while(b^=a^=b^=a%=b);
    return a;
}

bool check(ll x)
{
    for(int i=k; i; i--)
    {
        if(m[i]%x == 0) return 0;
        if(m[i] < x) break;
    }
    return 1;
}

int main()
{
    n = read(); k = read();
    for(ll i=1; i<=k; i++) m[i] = read();
    ll gcc = gcd(m[k], n);
    k--;
    for(ll i=1; i<=k; i++) m[i] = gcd(gcc, m[i]);
    sort(m+1, m+k+1);
    k = unique(m+1, m+k+1)-m-1;
    ll ans = gcc;
    for(ll i=1; i<=sqrt(gcc); i++)
    {
        if(gcc % i == 0)
        {
            if(i<ans && check(i)) ans = i;
            if(gcc/i<ans && check(gcc/i)) ans = gcc/i;
        }
    }
    printf("%lld\n", n/ans);
    
    return 0;
}

 

C. 追逐

直接鹤:来自%%%Chen_jr,都成洛古题解了%%%%%

code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 4;
const int N = 9e4 + 3;
const int inf = 0x3f3f3f3f;

int n, m, f[maxn], sum;
ll ans, tmp[maxn][105][2], g[maxn];

struct node 
{
    int next, to;
}a[maxn<<1];
int head[maxn], len;

void add(int x, int y)
{
    a[++len].to = y; a[len].next = head[x];
    head[x] = len;
}

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

void solve(int x, int fa)
{
    g[x] = 0;
    for(int i=1; i<=sum; i++) tmp[x][i][0] = 0;
    for(int i=head[x]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == fa) continue;
        g[x] += f[v];
        solve(v, x);
        for(int j=1; j<=sum; j++) tmp[x][j][0] = max(tmp[x][j][0], max(tmp[v][j][1], tmp[v][j][0]));
    }
    for(int i=sum; i>=1; i--) tmp[x][i][1] = tmp[x][i-1][0] + g[x];
}

int rmx[maxn][405];
ll rval[maxn][105], rcm[maxn][105];

void ch(int x, int fa)
{
    for(int i=1; i<=sum; i++) tmp[x][i][0] = max(tmp[x][i][0], max(tmp[fa][i][0], tmp[fa][i][1]));
    for(int i=1; i<=sum; i++) tmp[x][i][1] = tmp[x][i-1][0] + g[x] + f[fa];
    ans = max(ans, max(tmp[x][sum][0], tmp[x][sum][1]));
    for(int i=1; i<=sum; i++) tmp[x][i][0] = max(tmp[fa][i][0], tmp[fa][i][1]);
    for(int i=head[x]; i; i=a[i].next)
    {
        int v = a[i].to;
        for(int k=1; k<=sum; k++)
        {
            ll val = 0;
            //这个if else不是一样的吗??
            if(v == fa) val = max(tmp[fa][k][0], tmp[fa][k][1]);
            else val = max(tmp[v][k][0], tmp[v][k][1]);
            if(val > rval[x][k])
            {
                rcm[x][k] = rval[x][k];
                rval[x][k] = val;
                rmx[x][k] = v;
            }
            else rcm[x][k] = max(rcm[x][k], val);
        }
    }
    for(int i=head[x]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == fa) continue;
        for(int j=1; j<=sum; j++) tmp[x][j][0] = rmx[x][j] == v ? rcm[x][j] : rval[x][j];
        for(int j=1; j<=sum; j++) tmp[x][j][1] = tmp[x][j-1][0] + g[x] - f[v] + f[fa];
        ch(v, x);
    }
}

int main()
{  
    n = read(); sum = read();
    for(int i=1; i<=n; i++) f[i] = read();
    for(int i=1; i<n; i++)
    {
        int u = read(), v = read();
        add(u, v); add(v, u);
    }
    if(n == 1 || sum == 0)
    {
        printf("0\n"); exit(0);
    }
    if(n == 2)
    {
        printf("%d\n", max(f[1], f[2]));
        exit(0);
    }
    solve(1, 0);
    ch(1, 0);
    printf("%lld\n", ans);
    
    return 0;
}

 

D. 字符串

没时间写博客就只能鹤……

还是引个流吧

code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 5e5 + 4;
const int N = 9e4 + 3;
const int inf = 0x3f3f3f3f;

int n;
char c[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct node 
{
    int pre, suf, mx, sum;
}t[maxn<<2];

struct tree 
{
    void pushup(int x)
    {
        int ls = x<<1, rs = x<<1|1;
        t[x].sum = t[ls].sum + t[rs].sum;
        t[x].pre = max(t[ls].pre, t[ls].sum + t[rs].pre);
        t[x].suf = max(t[rs].suf, t[rs].sum + t[ls].suf);
        t[x].mx = max(max(t[x].pre, t[x].suf), max(t[ls].mx, t[rs].mx));
        t[x].mx = max(t[x].mx, t[ls].suf + t[rs].pre);
    }
    void build(int x, int l, int r)
    {
        if(l == r)
        {
            t[x].pre = t[x].suf = t[x].sum = t[x].mx = (c[l]=='C') ? 1 : -1;
            if(t[x].mx < 0) t[x].mx = 0;
            return;
        }
        int mid = (l + r) >> 1;
        build(x<<1, l, mid);
        build(x<<1|1, mid+1, r);
        pushup(x);
    }
    node query(int x, int l, int r, int L, int R)
    {
        if(L <= l && r <= R) return t[x];
        int mid = (l + r) >> 1;
        if(L <= mid && R > mid)
        {
            node p = query(x<<1, l, mid, L, R);
            node s = query(x<<1|1, mid+1, r, L, R);
            node ans;
            ans.sum = p.sum + s.sum;
            ans.pre = max(p.pre, p.sum + s.pre);
            ans.suf = max(s.suf, s.sum + p.suf);
            ans.mx = max(max(ans.pre, ans.suf), max(p.mx, s.mx));
            ans.mx = max(ans.mx, p.suf + s.pre);
            return ans;
        }
        if(L <= mid) return query(x<<1, l, mid, L, R);
        return query(x<<1|1, mid+1, r, L, R);
    }
}T;

int main()
{  
    n = read();
    scanf("%s", c+1);
    T.build(1, 1, n);
    int q = read();
    while(q--)
    {
        int l = read(), r = read();
        node ans = T.query(1, 1, n, l, r);
        printf("%d\n", ans.mx-ans.sum);
    }
    
    return 0;
}

 

posted @ 2022-09-30 19:30  Catherine_leah  阅读(20)  评论(2编辑  收藏  举报
/* */