2024.11.27

NOIP倒计时3天
今日总结:上午机房断网比赛,下午改题,晚上重新看了看以前写过的题
1:最大跨距
这道题我是用字符串中的stl解决的,当然更加准确的是用KMP来解决,只需要记录第一个访问的位置,和最后一个访问的位置

点击查看代码
#include<bits/stdc++.h>

using namespace std;

int main()
{
//	freopen("dis.in","r",stdin);
//	freopen("dis.out","w",stdout);
	string s,s1,s2;
	getline(cin,s,',');
	getline(cin,s1,',');
	cin >> s2;
	int l = s.find(s1);
	int len = s1.length();
	int r = s.rfind(s2);
	if(l > r || l == -1 || r == -1) printf("-1\n");
	else printf("%d\n",r - l - len);
	return 0;
}

2:都市
这道题正解是贪心,只需要对原来的序列进行排序,只需要枚举第一个数字的产生数量,再判一下重就行了,考试的时候没看出来,弄不出来样例

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 310,M = N * N;

int n,m,cnt;
int sum[M],p[M],ans[N][N];
bool b[M];

void Check(int x)
{
	memset(b,0,sizeof(b));
	if((sum[1] + sum[2] + sum[x]) & 1) return;
	p[1] = (sum[1] + sum[2] + sum[x]) / 2 - sum[x];
	p[2] = sum[1]-p[1];
	p[3] = sum[2] - p[1];
	b[1] = b[2] = b[x] = true;
	for(int i = 4,j = 3;i <= n;i ++)
    {
		while(j <= m && b[j]) j ++;
		if(j > m) return;
		p[i] = sum[j] - p[1];
		b[j] = true;
		for(int k = 2;k < i;k ++)
        {
			if (p[k] > p[i]) return;
			int v = p[k] + p[i],l = lower_bound(sum + 1,sum + m + 1,v) - sum,lb = l;
			if(sum[l] != v) return;
			while(lb && sum[lb] == sum[l]) lb --;
			lb ++;
			while(lb<=m&&sum[lb]==sum[l]&&b[lb]) lb ++;
			if(sum[lb] != sum[l] || b[lb]) return;
			l = lb;
			b[l] = true;
		}
	}
	cnt ++;
	for(int i = 1;i <= n;i ++)
		ans[cnt][i] = p[i];
}

int main()
{
    // freopen("city.in","r",stdin);
    // freopen("city.out","w",stdout);
    scanf("%d",&n);
    m = n * (n - 1) / 2;
    for(int i = 1;i <= m;i ++)
        scanf("%d",&sum[i]);
    sort(sum + 1,sum + m + 1);
    for(int i = 3,j = i;i <= m;i = j)
    {
		Check(i);
		while(j <= m && sum[j] == sum[i]) j ++;
	}
	printf("%d\n",cnt);
	for(int a = 1;a <= cnt;a ++)
    {
        for(int b = 1;b <= n;b ++)
        {
			printf("%d",ans[a][b]);
			if(b == n) printf("\n");
			else printf(" ");
		}
    }
    return 0;
}

3:最小生成树
这道题主要是依靠拓扑序来解决,但是我在考场上只想到了用并查集去维护最后两个点超时了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9 + 7;
const int N = 408, M = 21, S = (1 << M);
int res, n, m;
ll dp[S], ans[S][4];
int a[N], b[N];
int h[N], nxt[N], cnt, v[N], t[N];
void add(int x, int y, int z)
{
	t[++cnt] = y;
	v[cnt] = z;
	nxt[cnt] = h[x];
	h[x] = cnt;
}
void dfs(int x, int f, int y, int dis)
{
	if (y == x)
	{
		res = dis;
		return;
	}
	for (int i = h[x]; i; i = nxt[i])
	{
		if (t[i] == f)
			continue;
		dfs(t[i], x, y, (dis | (1 << (v[i]))));
	}
}

ll ksm(ll x, ll y)
{
	ll res = 1;
	while (y)
	{
		if (y & 1)
			res = res * x % mod;
		x = x * x % mod;
		y >>= 1;
	}
	return res;
}
ll jc[N + 5], inv[N + 5];
void init()
{
	jc[0] = 1;
	for (int i = 1; i <= N; i++)
		jc[i] = jc[i - 1] * i % mod;
	inv[N] = ksm(jc[N], mod - 2);
	for (int i = N - 1; i >= 0; i--)
		inv[i] = inv[i + 1] * (i + 1) % mod;
}
inline int read()
{
	int F = 1, ANS = 0;
	char C = getchar();
	while (C < '0' || C > '9')
	{
		if (C == '-')
			F = -1;
		C = getchar();
	}
	while (C >= '0' && C <= '9')
	{
		ANS = ANS * 10 + C - '0';
		C = getchar();
	}
	return F * ANS;
}

int main()
{
	init();
	n = read(), m = read();
	for (int i = 1; i < n; i++)
	{
		int x = read(), y = read();
		a[i] = x, b[i] = y;
		add(x, y, i - 1), add(y, x, i - 1);
	}
	int s = (1 << (n - 1)) - 1;
	for (int i = n; i <= m; i++)
	{
		int x = read(), y = read();
		dfs(x, 0, y, 0);
		// cout << res << endl;
		dp[s - res]++;
	}
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = (1 << (n - 1)) - 1; j >= 0; j--)
		{
			if (!(j & (1 << i)))
				dp[j] = (dp[j] + dp[j ^ (1 << i)]) % mod;
		}
	}
	ans[0][0] = 0, ans[0][1] = 0, ans[0][2] = 1, ans[0][3] = 0;
	for (int i = 1; i <= s; i++)
	{
		int u = i;
		ans[i][1] = __builtin_popcount(i);
		ans[i][0] = ans[i][1] + m - n + 1 - dp[i];
		while (u)
		{
			int v = (u & (-u)), w = (i ^ v);
			u ^= v;
			int l = dp[w] - dp[i];
			ans[i][2] = (ans[i][2] + ans[w][2] * inv[ans[w][0]] % mod * jc[ans[w][0] + l] % mod) % mod;
			ans[i][3] = (ans[i][3] + ans[w][3] * inv[ans[w][0] + 1] % mod * jc[ans[w][0] + l + 1] % mod) % mod;
		}
		ans[i][3] = (ans[i][3] + ans[i][1] * ans[i][2] % mod) % mod;
	}
	cout << ans[s][3];
	return 0;
}

4:测试数据
这道题可以写线段树用倍增优化,我只写了一个简单的线段树,没想到用倍增去优化,主要是实在是没有想到线段树还可以用倍增法,因为线段树本质上还是一个树

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n,m,Q;
int a[N];

struct Node
{
    int l,r;
}p[N];

struct SegmentTree
{
    int l,r,mx,add;
}tr[4 * N];

void pushup(int u)
{
    tr[u].mx = max(tr[u << 1].mx,tr[u << 1 | 1].mx);
}

void Build(int u,int l,int r)
{
    if(l == r) 
    {
        tr[u] = {l,r,a[l],0};
        return;
    }
    tr[u] = {l,r,0,0};
    int mid = (l + r) >> 1;
    Build(u << 1,l,mid),Build(u << 1 | 1,mid + 1,r);
    pushup(u);
}

void pushdown(int u)
{
    if(tr[u].add)
    {
        tr[u << 1].mx = tr[u << 1 | 1].mx = tr[u << 1 | 1].add = tr[u << 1].add = tr[u].add;
        tr[u].add = 0;
    }
}

void Modify(int u,int l,int r,int y)
{
    if(l <= tr[u].l && tr[u].r <= r)
    {
        tr[u].mx = tr[u].add = y;
        return;
    }
    pushdown(u);
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(l <= mid) Modify(u << 1,l,r,y);
    if(r > mid) Modify(u << 1 | 1,l,r,y);
    pushup(u);
}

int Query(int u,int l,int r)
{
    if(l <= tr[u].l && tr[u].r <= r) return tr[u].mx;
    pushdown(u);
    int mid = (tr[u].l + tr[u].r) >> 1,res = 0;
    if(l <= mid) res = max(res,Query(u << 1,l,r));
    if(r > mid) res = max(res,Query(u << 1 | 1,l,r));
    pushup(u);
    return res;
}

int main()
{
    // freopen("evaldate.in","r",stdin);
    // freopen("evaldate.out","w",stdout);
    scanf("%d%d%d",&n,&m,&Q);
    for(int i = 1;i <= n;i ++)
        scanf("%d",&a[i]);
    for(int i = 1;i <= m;i ++)
        scanf("%d%d",&p[i].l,&p[i].r);
    Build(1,1,n);
    int opt,x,y,z;
    while(Q --)
    {
        scanf("%d%d%d",&opt,&x,&y);
        if(opt == 2)
        {
            scanf("%d",&z);
            int Max;
            for(int i = x;i <= y;i ++)
            {
                Max = Query(1,p[i].l,p[i].r);
                Modify(1,p[i].l,p[i].r,Max);
            }
            printf("%d\n",Query(1,z,z));
            Build(1,1,n);
        }
        else
        {
            a[x] = y;
            Modify(1,x,x,y);
        }
    }
    return 0;
}

5:词链
这道题是一道欧拉回路的题目,当然也可以用并查集,这道题因为可能会出现相同的单词,所以用dfs去求欧拉路,考虑特性

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int N = 1010;

int n,ans,st;
int idx,to[N],w[N],d[N],nxt[N],head[N];
bool flag[N];
string s[N],tot[N];

void Add(int a,int b,int c)
{
    idx ++;
    to[idx] = b;
    w[idx] = c;
    d[a] ++,d[b] --;
    nxt[idx] = head[a];
    head[a] = idx;
}

void dfs(int u)
{
    for(int i = head[u];i;i = nxt[i])
    {
        int j = to[i],v = w[i];
        if(!flag[v])
        {
            flag[v] = true;
            dfs(j);
            ans ++;
            tot[ans] = s[v];
        }
    }
}

int main()
{
//     freopen("line.in","r",stdin);
//     freopen("line.out","w".,stdout);
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++)
        cin >> s[i];
    sort(s + 1,s + n + 1);
    st = s[1][0] - 'a' + 1;
    for(int i = n;i >= 1;i --)
    {
        int h = s[i][0] - 'a' + 1;
        int t = s[i][s[i].size() - 1] - 'a' + 1;
        Add(h,t,i);
    }
    for(int i = 1;i <= 26;i ++)
    {
        if(d[i] == 1) 
        {
            st = i;
            break;
        }
    }
    dfs(st);
    for(int i = 1;i <= n;i ++)
    {
        if(!flag[i]) 
        {
            printf("***");
            return 0;
        }
    }
    for(int i = ans;i > 1;i --)
        cout << tot[i] << ".";
    cout << tot[1] << endl;
    return 0;
}
posted @ 2024-11-27 21:52  Kevinhwbb  阅读(9)  评论(0编辑  收藏  举报