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;
}