2021杭电多校第四场

1004: Display Substring
二分+后缀自动机
后缀自动机的每个节点有\(a[i].len-a[a[i].fa].len\)个字符串,且是连续的后缀如\(acbc、cbc、bc\),所以对于每个节点
它的权值根据字符串由长到短是递减的,所以我们可以二分答案,再对每个节点利用前缀和二分判断这个节点有多少大于答案的值,就能得到结果

#include <bits/stdc++.h>
const int maxn=1e5+50;
using namespace std;
#define int long long
int head[maxn<<1],nex[maxn<<1],to[maxn<<1],ecnt;
int size[maxn];
long long ans=0;
int dp[maxn];
struct node {
	int ch[26];
	int len,fa;
	int pos;
} a[maxn<<1];
int pre=1,tot=1;
inline void init() {
	pre=tot=1;
	for(int i=0; i<26; i++) {
		a[1].ch[i]=0;
	}
	ans=0;
	a[1].len=0;
	a[1].fa=0;
	a[1].pos=0;
}
inline int newnode() {
	++tot;
	a[tot].len=0;
	a[tot].fa=0;
	a[tot].pos=0;
	for(int i=0; i<26; i++) {
		a[tot].ch[i]=0;
	}
	return tot;
}
inline void insert(int c,int i) {
	int p=pre,np=pre=newnode();
	size[tot]=1;
	a[np].pos=i;
	a[np].len=a[p].len+1;
	for(; p&&!a[p].ch[c]; p=a[p].fa) a[p].ch[c]=np;
	if(!p) a[np].fa=1;
	else {
		int q=a[p].ch[c];
		if(a[q].len==a[p].len+1) a[np].fa=q;
		else {
			int nq=newnode();
			a[nq]=a[q];
			a[nq].len=a[p].len+1;
			a[q].fa=a[np].fa=nq;
			for(; p&&a[p].ch[c]==q; p=a[p].fa) a[p].ch[c]=nq;
		}
	}
}
int n,k;
int w[maxn];
char s[maxn];
int cnt;
int sum[maxn];
inline int ok(int val) {
	int res=0;
	for(int i=2; i<=tot; i++) {
		int l=1,r=a[i].len-a[a[i].fa].len;
		while(l<=r) {
			int mid=l+r>>1;
			if(sum[a[i].pos]-sum[a[i].pos-mid-a[a[i].fa].len]>val)r=mid-1;
			else l=mid+1;
		}
		res=res+r;
	}
	if(res>=k)return 1;
	else return 0;
}
const int inf=1e10+10;
signed main() {
	int T;
	scanf("%lld",&T);
	int cas=0;
	while(T--) {
		cnt=0;
		scanf("%lld %lld",&n,&k);
		scanf("%s",s);
		int len=strlen(s);
		init();
		for(int i=0; i<len; i++) insert(s[i]-'a',i+1);
		for(int i=0; i<26; i++) {
			scanf("%lld",&w[i]);
		}
		for(int i=1; i<=n; i++) {
			sum[i]=sum[i-1]+w[s[i-1]-'a'];
		}
		int l=0,r=inf;
		while(l<=r) {
			int mid=l+r>>1;
			if(ok(mid))r=mid-1;
			else l=mid+1;
		}
		if(r!=inf) {
			printf("%lld\n",l);
		} else {
			printf("-1\n");
		}
		cas++;
	}
}

1008:Lawn of the Dead
转化为区间然后模拟一下
还有扫描线、并查集做法,不知道咋搞的

#include<bits/stdc++.h>
using namespace std;

#define int long long
typedef long long ll;
const int maxn = 1e5 + 10;

long long ans = 0;
int  n, m, k;
bool vis[1010][1001];
int mp[1001][1001];
void dfs(int x, int y) {
    if(x > n || y > m || vis[x][y] || mp[x][y]) return ;
    vis[x][y] = 1;
    ans ++;
    dfs(x + 1, y);
    dfs(x, y + 1);
}

int test() {
    scanf("%lld %lld %lld", &n, &m, &k);
    for(int i = 1; i <= n; ++ i)    for(int j = 1; j <= m; ++ j)   {
         vis[i][j] = 0; mp[i][j] = 0;
    }
    for(int i = 0; i < k; ++ i) {
        int x, y; scanf("%lld %lld", &x, &y);
        mp[x][y] = 1;
    }
    ans = 0;
    dfs(1, 1);
    printf("%lld\n", ans);
    return ans;
}
vector<int> v[maxn];
void run() {
    int n, m, k, x, y;    scanf("%d %d %d", &n, &m, &k);
    for(int i = 1; i <= n; ++ i)    v[i].clear();
    for(int i = 0; i < k; ++ i) {
        scanf("%d %d", &x, &y);
        v[x].push_back(y);
    }
    for(int i = 1; i <= n; ++ i)    sort(v[i].begin(), v[i].end());
    vector<pair<int, int>> seg, tmp;
    seg.push_back({1, 1});
    long long ans = 0;
    for(int i = 1; i <= n; ++ i) {
        int now = 0, up = seg.size(), r;
        if(!seg.size()) break;
        r = seg[0].first;
        for(auto it : v[i]) {
            if(it < seg[now].first) r = it + 1;
            else if(it == seg[now].first) {
                seg[now].first ++;
                if(seg[now].first > seg[now].second)    now ++;
                r = it + 1;
            }
            else {
                tmp.push_back({seg[now].first, it - 1});
                ans += it - seg[now].first;
                if(it < seg[now].second) {
                    seg[now].first = it + 1;
                    r = it + 1;
                }
                else {
                    now ++;
                    r = it + 1;
                    while(now < up) {
                        if(seg[now].second < r) {
                            now ++; continue;
                        }
                        seg[now].first = max(r, seg[now].first);
                        break;
                    }
                }
            }
            if(now == up)   break;
        }
        if(now < up) {
            tmp.push_back({max(seg[now].first, r), m});
            ans += m - max(seg[now].first, r) + 1;
        }
        seg = tmp;
        tmp.clear();
    }
    printf("%lld\n", ans);
}



signed main() {
    //printf("%lld\n", test());
    /*for(int i = 1; i <= n; ++ i)    {
        for(int j = 1; j <= m; ++ j)    cout << vis[i][j] << " ";
        cout << endl;
    }*/
    int t; scanf("%lld", &t);
    while(t--)  run();
    return 0;
}

posted @ 2021-07-29 18:19  wlhp  阅读(40)  评论(0)    收藏  举报