The 15th Jilin Provincial Collegiate Programming Contest

L .Suzuran Loves String

题意:

给出一串字符串,对所有可能的a、b求max【从a串到b串的最小操作数】
a、b均为该字符串的后缀字串
对a、b可进行删减、增加的操作。

题解:

思考肯定尽可能的让a、b长:a字符串取s本身。
如果a的前n项等于b的前n项,那这部分是不用进行删去、增加操作的,那么我们就让这部分尽可能短。(力求删去最多)但是仍要保证加上的最多。
写几个例子试试可以发现,遇到第一个s[0]不等于s[i],如果b的后缀取i后字符串,此时的操作数为删去a的所有,在加上i后的个数。此时为最大。
(若在i之前,【b需要增加的值】不变,但是【a需要减少的值减少】。)

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
const int maxn=1e5+7;
#define ll long long
const int mod=1e9+7; 
ll d[maxn];
ll a[maxn];
ll fs(ll x, ll n,ll p){
	ll res = 1;
       x%=p;
       while (n){ 
           if(n & 1)  res = (res * x )%p;
           n >>= 1;  
           x = (x * x)%p ;
       }
       return res;
}
ll get_inv(ll x,ll p){
       return fs(x,p-2,p);
}
void init(int n){
	a[1]=1;
	for(int i=2;i<=n;i++){
		a[i]=a[i-1]*i%mod;
		//cout<<a[i]<<endl;
	}
}
ll C(int n){
	init(2*n);
	return a[2*n]*get_inv(a[n],mod)%mod*get_inv(a[n],mod)%mod;
}
int main() {
	ll n,k;cin>>n>>k;
	ll ans=C(n)*get_inv(n+1,mod)%mod;
	ans=ans*fs(k,n,mod)%mod;
	cout<<ans<<endl;
	return 0;
}

K. Bracket Sequence

题意:

给出n对、k种括号。问有多少种合法的可能。

题解:

本题需要注意的是【一种括号时候有多少种情况】,因为只要算出这个值:sum。就可以求出k种了:sum*kn (k个位置n种直接计算)。以及本题需要运用【逆元】,不然精度损失太严重。

而一种括号时候有多少种情况为卡特兰数,具体请自己搜索。
附上几个链接:
转知乎
转CSDN

H. Visit the Park

本题具体见代码:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
const int mod=998244853;
const int maxn=3e5+7;
#define ll long long
ll a[maxn];
map< pair<int,int> , vector<int> >mp;
map< pair<int,int> , vector<int> >edge;
ll fs(ll x, ll n,ll p)
{
	ll res = 1;
       x%=p;
       while (n)
	   {
           if(n & 1)  res = (res * x )%p;
           n >>= 1; 
           x = (x * x)%p ;
       }
       return res;
}
ll ni(ll aoe){
	return fs(aoe,mod-2,mod);
}
int main() {
	int n,m,k;
	int u,v,w;
	sc("%d%d%d",&n,&m,&k);
	for(int i=1;i<=m;i++){
		sc("%d%d%d",&u,&v,&w);
		//只按照顺序存组: 
		if(u<v)mp[make_pair(u,v)].push_back(w);
		else mp[make_pair(v,u)].push_back(w);
	}
	ll ans=0;
	ll pos=1;
	ll t=ni(10);
	bool ok=1;
	for(int i=1;i<k-1;i++)pos=pos*10%mod;//最大那位要乘的数
	for(int i=1;i<=k;i++)sc("%d",&a[i]);
	for(int i=1;i<k;i++){
		int u=min(a[i],a[i+1]);
		int v=max(a[i],a[i+1]);//保证顺序从小到大-因为存只存了小到大
		vector<int> now=mp[make_pair(u,v)];
		int len=now.size();
		if(len==0){//没有路,break掉 
			ok=0;break;
		}
		ll key=ni(len);
		for(int j=0;j<len;j++){
			ans=(ans+((pos*now[j])%mod*key)%mod)%mod;//每一种选择的权重,要除以总和表示此位置的数值出现了几次 
		} 
		pos=pos*t%mod;//除去10表示下一位占的位置需要乘的10; 
	} 
	if (ok) cout << ans << endl;
    else cout << "Stupid Msacywy!" << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值