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 魔法森林
还没改完呢,咕咕咕。