11.21考试总结

T1 字符串

题目描述

小林与亮亮正在做一个游戏。小林随意地写出一个字符串,字符串只由大写字母组成,然后指定一个非负整数 (m),亮亮可以进行至多 (m) 次操作,每次操作为交换相邻两个字符。亮亮的目标是使得操作后的字符串出现最长相同的字符的长度最大。你能帮亮亮计算一下这个最大长度是多少吗?

字符串长度 (Lleq 50), (0leq mleq 5000).

solution

我们枚举一下长度最长的是哪个字符 (S),然后在枚举这个字符 (S) 的那个位置 (T) 保持不动。剩下的与他相同的字符向他靠近,分别计算出他们与选定字符 (T) 相邻需要挪动几次,贪心的选即可。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,ans,num[110],pos[110][110],b[110];
char s[110];
inline int read()
{
    int s = 0,w = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
    return s * w;
}
int calc(int x)
{
    int res = 0;
    if(num[x] <= 1) return num[x];
    for(int i = 1; i <= num[x]; i++)
    {
        int tot = 0, now = 1;
        for(int j = 1; j <= num[x]; j++)
        {
            b[j] = abs(pos[x][i] - pos[x][j]) - abs(j - i); 
        }
        sort(b+1,b+num[x]+1);
        while(now <= num[x] && tot + b[now] <= m){ tot += b[now]; now++; }
        res = max(res,now-1);
    }
    return res;
}
int main()
{
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
    scanf("%s",s+1); m = read();
    n = strlen(s+1);
    for(int i = 1; i <= n; i++)
    {
        int c = s[i] - 'A';
        pos[c][++num[c]] = i;
    }
    for(int i = 0; i <= 25; i++)
    {
        ans = max(ans,calc(i));
    }
    printf("%d
",ans);
    fclose(stdin); fclose(stdout);
    return 0;
}

T2 桃园之礼

给你一个 $n imes m $ 的网格图,里面有 (k) 个点要经过,坐标分别为 ((x_1,y_1,x_2,y_2...x_k,y_k)) .让你求从 ((1,1)-(n,m)) 且进过所有 (k) 的点的方案数有多少个,输出答案模 (10^8) 的结果即可

solution

Exlucas + 中国剩余定理。

显然每个点经过的顺序是固定的,先对 (k) 个点排一下序,就得到了这个顺序序列。

然后问题转化为从 ((x_{i-1},y_{i-1})-(x_i,y_i)) 有多少种方案数。根据分步乘法计数原理可知把每个 (i) 的答案乘起来就是最后的答案。

((x_{i-1},y_{i-1})-(x_i,y_i))(C_{{x_i}-x_{i-1} + y_i-y_{i-1}}^{x_i-x_{i-1}}) 种。

具体证明一下:问题可以分解为 在一个 (n imes m) 的矩形中,从左上角走到右下角共有几种走法。我们一共要走 (n+m-2) 步,其中向下走 (n-1) 步。这 (n-1) 步的位置可以是随意的,也就是从 (n+m-2) 步中任选 (n-1) 步向下走,方案数显然是 (C_{n+m-2}^{n-1}) .

又因为模数不是质数,所以只能用 (Exlucas).

emmm,(Exlucas) 的学习笔记有空再补吧。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod = 1e8;
#define int long long
int n,m,k,ans = 1;
struct node
{
	int x,y;
}e[100010];
inline int read()
{
    int s = 0,w = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
    return s * w;
}
bool comp(node a,node b)
{
	if(a.y == b.y) return a.x < b.x;
	return a.y < b.y;
}
void exgcd(int a,int b,int &x,int &y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return;
	}
	exgcd(b,a%b,y,x);
	y -= a / b * x;
}
int inv(int a,int b)
{
	int x = 0, y = 0;
	if(!a) return 0;
	exgcd(a,b,x,y);
	x = (x % b + b) % b;
	return x;
}
int ksm(int a,int b,int p)
{
	int res = 1;
	for(; b; b >>= 1)
	{
		if(b & 1) res = res * a % p;
		a = a * a % p;
	}
	return res;
}
int fac(int n,int pi,int pk)
{
	if(n == 0 || n == 1) return 1;
	int ans = 1, tmp1 = 1, tmp2 = 1;
	for(int i = 1; i <= pk; i++)
	{
		if(i % pi) tmp1 = tmp1 * i % pk;
	}
	for(int i = 1; i <= n%pk; i++)
	{
		if(i % pi) tmp2 = tmp2 * i % pk;
	}
	return fac(n/pi,pi,pk) % pk * ksm(tmp1,n/pk,pk) % pk * tmp2 % pk;
}
int C(int n,int m,int pi,int pk)
{
	int n1 = fac(n,pi,pk), m1 = fac(m,pi,pk), m2 = fac(n-m,pi,pk);
	int x = 0, y = 0, z = 0;
	for(int i = n; i; i /= pi) x += i/pi;
	for(int i = m; i; i /= pi) y += i/pi;
	for(int i = n-m; i; i /= pi) z += i/pi;
	return n1 * inv(m1,pk) * inv(m2,pk) * ksm(pi,x-y-z,pk);
}
int Exlucas(int n,int m,int p)
{
	int P = p, ans = 0, pi, pk;
	for(int i = 2; i <= p; i++)
	{
		if(p % i == 0)
		{
			pi = i, pk = 1;
			while(p % i == 0) p /= i, pk *= i;
			ans = (ans + C(n,m,pi,pk) * (P/pk) % P * inv(P/pk,pk) % P) % P; 
		}
	}
	return ans;
}
signed main()
{
	freopen("peach.in","r",stdin);
	freopen("peach.out","w",stdout);
	n = read(); m = read(); k = read();
	for(int i = 1; i <= k; i++)
	{
		e[i].x = read();
		e[i].y = read();
	}
	e[k+1].x = 1; e[k+1].y = 1;
	e[k+2].x = n; e[k+2].y = m;
	sort(e+1,e+k+3,comp);
	for(int i = 2; i <= k+2; i++)
	{
		int nn = e[i].x - e[i-1].x + 1;
		int mm = e[i].y - e[i-1].y + 1;
		if(nn <= 0 || m <= 0) 
		{
			printf("%d
",0);
			return 0;
		}
		ans = ans * Exlucas(nn+mm-2,mm-1,mod) % mod;
	}
	printf("%lld
",ans);
	fclose(stdin); fclose(stdout);
	return 0;
}

T3 魔法森林

还没改完呢,咕咕咕。

原文地址:https://www.cnblogs.com/genshy/p/14034690.html