2022NOIPA层联测18

B. 刷墙(b)

刷墙:
WA的原因是:我让每个数试图插入他之前的任意位置,但其实这个区间不可以任意划分
本来就存在的前后关系可能被打乱,被覆盖的在i之上,没被覆盖的在i之下,就假了。。
但我枚举时间顺序那个不至于错吧,好吧,它对了
可是为什么可以区间dp,大小区间并不可以累加吧
通过统计区间包含的区间个数然后判断,到底统计的是区间的个数还是颜色的个数?
f[l][r]只考虑被完全包含的小区间,没有跨越端点的应该可以合并了。。
题目说l小于r,那么长度为1的区间是不存在了,可是先放的[x, x+1]又被覆盖了怎么办?
要不然先改T3?
关于题意理解:从第li米到第ri米,所以li指的是点而不是一段长度的区间!?
所以l小于r这件事就好理解了。。。
良心新数据,成功地把我卡了:
3
1 4
1 2
3 4
所以暴力怎么写。。。每个点就代表他之后的一段就好了
TLE+假做法=27pts
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 303;

int n, c[maxn<<1], ans, ls[maxn<<1], cnt, res, d[maxn<<1], rem[maxn<<1];
bool vis[maxn];
set<int> s;

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 l, r;
}p[maxn];

void check(int num, int m, int l, int r, int col)
{
    s.clear();
    for(int i=1; i<=m; i++)
    {
        if(num & (1<<i-1)) s.insert(i);
    }
    memcpy(d, c, sizeof(c));
    for(int i=l; i<=r; i++)
    {
        if(s.find(d[i]) != s.end()) continue;
        d[i] = col;
    }
    int yys = 0;
    for(int i=1; i<=n; i++) vis[i] = 0;
    for(int i=1; i<=cnt; i++) vis[d[i]] = 1;
    for(int i=1; i<=n; i++) if(vis[i]) yys++;
    if(yys <= res) return;
    memcpy(rem, d, sizeof(rem));
    res = yys;
}

int a[12];
inline bool query(int l, int r)
{
    for(int i=l; i<=r; i++) if(c[i] == 0) return true;
    return false;
}

inline void update(int l, int r, int col)
{
    for(int i=l; i<=r; i++) if(!c[i]) c[i] = col;
}

void solve()
{
    for(int i=1; i<=n; i++) a[i] = i;
    do 
    {
        int res = 0;
        for(int i=1; i<=cnt; i++) c[i] = 0;
        for(int i=1; i<=n; i++)
        {
            for(int j=p[a[i]].l; j<p[a[i]].r; j++)
            {
                c[j] = i;
            }
        }
        for(int i=1; i<=n; i++) vis[i] = 0;
        for(int i=1; i<=cnt; i++) vis[c[i]] = 1;
        for(int i=1; i<=n; i++) if(vis[i]) res++;
        ans = max(ans, res);
    }while(next_permutation(a+1, a+1+n));
    printf("%d\n", ans);
    exit(0);
}

int main()
{
    freopen("b.in", "r", stdin);
    freopen("b.out", "w", stdout);
    
    n = read();
    for(int i=1; i<=n; i++)
    {
        p[i].l = read(); p[i].r = read(); 
        ls[++cnt] = p[i].l; ls[++cnt] = p[i].r;
    }
    sort(ls+1, ls+1+cnt); cnt = unique(ls+1, ls+1+cnt)-ls-1;
    for(int i=1; i<=n; i++)
    {
        int l = p[i].l, r = p[i].r;
        p[i].l = lower_bound(ls+1, ls+1+cnt, l)-ls;
        p[i].r = lower_bound(ls+1, ls+1+cnt, r)-ls;
    }
    if(n <= 10) solve();
    for(int i=1; i<=n; i++)
    {
        int Max = 1 << i-1; res = 0;
        for(int j=0; j<Max; j++)
        {
            check(j, i-1, p[i].l, p[i].r, i);
        }
        if(res > ans) memcpy(c, rem, sizeof(rem)), ans = res;
    }
    ans = 0;
    for(int i=1; i<=n; i++) vis[i] = 0;
    for(int i=1; i<=cnt; i++) vis[c[i]] = 1;
    for(int i=1; i<=n; i++) if(vis[i]) ans++;
    printf("%d\n", ans);

    return 0;
}
 
所以解决最后一段是否重复的问题只需要把前缀和再减回去,check一下[k, k+1]是不是可以完全包含某区间
code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 603;

int n, ans, ls[maxn], cnt, f[maxn][maxn], sum[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;
}

struct node 
{
    int l, r;
}p[303];

int get(int l1, int l2, int r1, int r2)
{
    return sum[l2][r2] - sum[l1-1][r2] - sum[l2][r1-1] + sum[l1-1][r1-1];
}

int main()
{
    freopen("b.in", "r", stdin);
    freopen("b.out", "w", stdout);
    
    n = read();
    for(int i=1; i<=n; i++)
    {
        p[i].l = read(); p[i].r = read(); 
        ls[++cnt] = p[i].l; ls[++cnt] = p[i].r;
    }
    sort(ls+1, ls+1+cnt); cnt = unique(ls+1, ls+1+cnt)-ls-1;
    for(int i=1; i<=n; i++)
    {
        int l = p[i].l, r = p[i].r;
        p[i].l = lower_bound(ls+1, ls+1+cnt, l)-ls;
        p[i].r = lower_bound(ls+1, ls+1+cnt, r)-ls;
    }
    for(int i=1; i<=n; i++)
    {
        sum[p[i].l][p[i].r]++;
    }
    for(int i=1; i<=cnt; i++)
    {
        for(int j=1; j<=cnt; j++)
        {
            sum[i][j] = sum[i][j]-sum[i-1][j-1]+sum[i-1][j]+sum[i][j-1];
        }
    }
    for(int len=1; len<=cnt; len++)
    {
        for(int l=1,r; (r=l+len-1)<=cnt; l++)
        {
            for(int k=l; k<r; k++)
            {
                f[l][r] = max(f[l][r], f[l][k]+f[k+1][r]+(get(l,k,k+1,r)>0));
            }
        }
    }
    printf("%d\n", f[1][cnt]);

    return 0;
}
 
 

C. 重复(c)

重复:
我好奇000010是怎么被我算成合法解的。。
取substr的时候算错数了。。还有一个上界设错了
然而用string函数比较的复杂度似乎并不对,改成hash会快一点,不过细节变多了。。比如下标的相对关系不能变
不过hash真的是比string快了不是一点半点!!!
https://www.cnblogs.com/Catherine2006/p/16758108.html
好像早就发现过这个结论
TLE 27
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 303;

string s1;
int n, m, ans;

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 check(string s)
{
    n = s.size(); //int n1 = n / 3 + 1, n2 = (n - n1) / 2;
    for(int i=1; i<=n; i++)
    {
        string a = s.substr(0, i), b = s.substr(i, i);
        //printf("i = %d\n", i);
        if(a != b) continue;
        for(int j=1; j<=n; j++)
        {
            if(n - j - i <= i + i + j) continue;//这个等号并没有问题。。
            //printf("n-j = %d i+i = %d j = %d\n", n-j, i+i, j);
            string f = s.substr(n-j, j), c = s.substr(i+i, j);
            if(c != f) continue;
            //printf("n-j-i+1 = %d i = %d\n", n-j-i+1, i);
            string e = s.substr(n-j-i, i);
            if(a != e) continue;
            //cout << a << " " << b << " " << c << " " << e << " " << f << endl;
            ans++;
            //printf("ans = %d\n", ans);
        }
    }
}

int main()
{
    freopen("c.in", "r", stdin);
    freopen("c.out", "w", stdout);
    
    cin >> s1;
    //string s = "000110";
    //check(s);
    m = s1.size(); 
    for(int len=6; len<=m; len++)
    {
        for(int i=0; i+len-1<m; i++)
        {
            //printf("i = %d len = %d\n", i, len);
            string s = s1.substr(i, len);
            //cout << s << endl;
            check(s);
        }
    }
    printf("%d\n", ans);

    return 0;
}

TLE 55
// ubsan: undefined
// accoders
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const int maxn = 5007;

string s1;
int n, m, ans;
ull h[maxn], jc[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 ull gethash(int l, int r)
{
    if(l == 0) return h[r];
    return h[r] - h[l-1] * jc[r-l+1];
}

inline void check(int l, int n)
{
    for(int i=1; i<=n; i++)
    {
        if(gethash(l, l+i-1) != gethash(l+i, l+i+i-1)) continue;
        for(int j=1; j<=n; j++)
        {
            if(n - j - i <= i + i + j) continue;
            if(gethash(l+n-j, l+n-1) != gethash(l+i+i, l+i+i+j-1)) continue;
            if(gethash(l, l+i-1) != gethash(l+n-j-i, l+n-j-1)) continue;
            //cout << s1.substr(l, i) << " " << s1.substr(l+i, i) << " " << s1.substr(l+i+i, j) << " " << s1.substr(l+n-j-i, i) << " " << s1.substr(l+n-j, j) << endl;
            ans++;
        }
    }
}

void init()
{
    h[0] = s1[0] - '0' + 1;
    for(int i=1; i<m; i++)
    {
        h[i] = h[i-1] * 131 + s1[i] - '0' + 1;
    }
    jc[0] = 1;
    for(int i=1; i<=m; i++)
    {
        jc[i] = jc[i-1] * 131;
    }
}

int main()
{
    freopen("c.in", "r", stdin);
    freopen("c.out", "w", stdout);
    
    cin >> s1;
    m = s1.size();
    init();
    for(int len=6; len<=m; len++)
    {
        for(int i=0; i+len-1<m; i++)
        {
            //string s = s1.substr(i, len);
            //check(s);
            check(i, len);
        }
    }
    printf("%d\n", ans);

    return 0;
}

 
At last,根据AABCAB预处理一下AB的个数,用hash判断AA
code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const int maxn = 5007;

int n;
char s[maxn];
ll cnt[maxn][maxn], ans;
ull h[maxn], jc[maxn];
map<ull, ll> mp;

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 ull gethash(int l, int r)
{
    return h[r] - h[l-1] * jc[r-l+1];
}

int main()
{
    freopen("c.in", "r", stdin);
    freopen("c.out", "w", stdout);
    
    scanf("%s", s+1);
    n = strlen(s+1);
    h[1] = s[1] - '0';
    for(int i=2; i<=n; i++)
    {
        h[i] = h[i-1] * 131 + s[i] - '0';
    }
    jc[0] = 1;
    for(int i=1; i<=n; i++)
    {
        jc[i] = jc[i-1] * 131;
    }
    for(int len=1; len<=n; len++)
    {
        mp.clear();
        for(int l=n-len+1; l>=1; l--)
        {
            int r = l + len - 1;
            if(mp.find(gethash(l, r)) != mp.end()) cnt[l][r] = mp[gethash(l, r)];
            if(r+len<=n) mp[gethash(l+len, r+len)]++;
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=n; j>=i; j--) cnt[i][j] += cnt[i][j+1];
    }
    for(int l=1; l<=n; l++)
    {
        for(int r=l+1; r<=n; r+=2)
        {
            int len = (r - l + 1) / 2;
            if(gethash(l, l+len-1) != gethash(l+len, r)) continue;
            ans += cnt[l+len][r+1];
        }
    }
    printf("%lld\n", ans);

    return 0;
}
 
posted @ 2022-10-31 20:07  Catherine_leah  阅读(8)  评论(0编辑  收藏  举报
/* */