8/17 牛客训练营9补题+cf(BC)
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了8/17 牛客训练营9补题+cf(BC)相关的知识,希望对你有一定的参考价值。
B-Two Frogs
题意:两只青蛙从荷叶1跳到荷叶n,每个荷叶可跳的范围是(i,i+a[i]]
(左开右闭),问两只青蛙跳到荷叶n的概率是多少?
所用知识:前缀和、差分、dp
思路:
1.设计状态dp[i][j]
:表示所用j步跳到荷叶i的概率是多少
2.状态的转移:当前青蛙可跳的荷叶数为(i,i+a[i]]
,共有a[i]个荷叶可供选择。因此这段区间dp[i+1~i+a[i]][j+1]
的概率都为dp[i][j]/a[i]
.
3.由此可看出是区间值得累加,因此想到差分。dp[i+1][j+1]
加上概率dp[i][j]/a[i]
,而dp[i+a[i]+1][j+1]
则减去概率dp[i][j]/a[i]
4.在每次对dp[i][j]进行操作时,要写一个for循环进行前缀和得累加。
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=8e3+5;;
const int inf=0x3f3f3f3f;
const int mod=998244353;
int n,a[N],b[N],dp[N][N];
int qpow(int x,int y)
int res=1;
while(y)
if(y&1)
res=res*x%mod;
x=x*x%mod;
y>>=1;
return res;
void solve()
cin>>n;
for(int i=1;i<n;i++)
cin>>a[i],b[i]=qpow(a[i],mod-2);
dp[1][0]=1;
dp[2][0]=-1;
for(int i=1;i<=n;i++)
for(int k=0;k<i;k++)
//前缀和更新
dp[i][k]=(dp[i][k]+dp[i-1][k])%mod;
//差分
dp[i+1][k+1]=(dp[i+1][k+1]+dp[i][k]*b[i])%mod;
dp[i+a[i]+1][k+1]=(dp[i+a[i]+1][k+1]-dp[i][k]*b[i])%mod;
int ans=0;
for(int i=1;i<n;i++)
ans=(ans+dp[n][i]*dp[n][i]%mod)%mod;
cout<<ans<<endl;
signed main()
//ios;
solve();
return 0;
G-Two Frogs
题意:给定n个字符串,问有多少个回文串的数量出现在这n个字符串中?
所用知识:马拉车算法、哈希算法
思路:
1.先采用双哈希算法来降低字符串记录数值的冲突
2.在采用马拉车算发记录有多少本质不同的回文串。
3.减枝。若当前字符串出现次数<id-1,则肯定不满足出现n次;
若出现次数等于n,则说明该字符串中已被统计过,无需重复记录。
若id>1,但还字符串还没出现过,统计次数为0,则无需统计。
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+6;;
const int inf=0x3f3f3f3f;
const int mod1=1000000007,mod2=998244353,base=131;
map<pair<int,int>,int>mp;
char ch[N],s[N];
//双哈希,进行两次哈希降低冲突
int sum1[N],sum2[N],pow1[N],pow2[N],n,G;
void init()
pow1[0]=pow2[0]=1;
for(int i=1;i<=300000;i++)
pow1[i]=pow1[i-1]*base%mod1;
pow2[i]=pow2[i-1]*base%mod2;
void init_str(char *s)
int n=strlen(s+1);
ch[0]='@',ch[n*2+1]='#',ch[n*2+2]='\\0';
sum1[0]=sum2[0]=0;
for(int i=1;i<=n;i++)
sum1[i]=(sum1[i-1]*base%mod1+s[i])%mod1;
sum2[i]=(sum2[i-1]*base%mod2+s[i])%mod2;
ch[i*2]=s[i];
ch[i*2-1]='#';
G=2*n+1;
pair<int,int> get_hash(int l,int r)
int hash1 =(sum1[r] - sum1[l-1] * pow1[r - l + 1] % mod1 + mod1) % mod1;
int hash2 =(sum2[r] - sum2[l-1] * pow2[r - l + 1] % mod2 + mod2) % mod2;
return hash1, hash2;
//马拉车算法,求出多少个本质不同的回文子串
int r[N];
void manacher(int id)
r[1]=1;
int k=1;
for(int i=2;i<=G;i++)
int p=k+r[k]-1;
if(i<=p)
r[i]=min(r[2*k-i],p-i+1);
else r[i]=1;
while(ch[i-r[i]]==ch[i+r[i]]) r[i]++;
if(i+r[i]>k+r[k])
for(int rr=k+r[k]+1;rr<=i+r[i];rr++)
int l=2*i-rr;
if(ch[rr]=='#')
pair<int,int> hv=get_hash(l/2+1,rr/2);
if((id>1&&!mp.count(hv))||(mp[hv]==id))
continue;
if(id>1&&mp[hv]<id-1)
mp.erase(hv);continue;
mp[hv]=id;
k=i;
void solve()
init();
cin>>n;
for(int i=1;i<=n;i++)
scanf("%s",s+1);
init_str(s);
manacher(i);
int ans=0;
for(auto x:mp)
if(x.second==n)
ans++;
cout<<ans<<endl;
signed main()
//ios;
solve();
return 0;
B. Mathematical Circus
这题确实有个点没想到。有点蒙蔽了,还老走神。。。。算想了个复杂的思路过的题。
思路:
1.将n个数分为4组,对4取模,0、1、2、3的分别为1组。
2.看似除了对2取模,其他输出1,2,3,4组中元素输出即可。
但其中是有规律的,但其中一个规律没找出来,导致做的很烦躁:
1.首先对4取模结果为0,是无法分组的:k不管和1、2、3谁组,都无法恰好分为2类
2.若对4取模结果为1,有两类分组情况,但其中一种情况是可行的:
第一类:(k+3组) 和 1组 形成pair 。 k+3组是可形成4的倍数,但不优。2组和4组形成一个pair
第二类:(k+2组) 和 2组 形成pair。看似没形成4的倍数,实则(k+2)组贡献了一个因子2,2组也天然带一个因子2.
第二类更优的情况是因为1组和2组形成pair,无需n是4的倍数。而第一类的前提条件是必须为4的倍数。
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define maxn 1000000000LL
#define ULL unsigned long long
using namespace std;
const int N=7e6+10;
const int inf=0x3f3f3f3f;
const int mod=1e7+7;
int n,k,a[N],b[N],c[N],d[N];
int g1,g2,g3,g4;
void solve()
cin>>n>>k;
g1=g2=g3=g4=0;
for(int i=1;i<=n;i++)
if(i%4==1) a[++g1]=i;
else if(i%4==2) b[++g2]=i;
else if(i%4==3) c[++g3]=i;
else if(i%4==0) d[++g4]=i;
if(k%4==0)
cout<<"NO"<<endl;
if(k%4==1)
cout<<"YES"<<endl;
for(int i=1;i<=g1;i++)
cout<<a[i]<<" "<<b[i]<<endl; // 3 1
for(int i=1;i<=g3;i++)
cout<<c[i]<<" "<<d[i]<<endl; // 2 4
if(k%4==2)
cout<<"YES"<<endl;
for(int i=1;i<=g1;i++)
cout<<b[i]<<" "<<a[i]<<endl; // 2 1
for(int i=1;i<=g3;i++)
cout<<c[i]<<" "<<d[i]<<endl; // 3 4
if(k%4==3)
cout<<"YES"<<endl;
for(int i=1;i<=g1;i++)
cout<<a[i]<<" "<<b[i]<<endl; // 1 2
for(int i=1;i<=g3;i++)
cout<<c[i]<<" "<<d[i]<<endl; // 3 4
signed main()
int t;cin>>t;
while(t--)
solve();
return 0;
C. Fighting Tournament
B题想复杂了,导致C题没心情去看。。。
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define maxn 1000000000LL
#define ULL unsigned long long
using namespace std;
const int N=7e6+10;
const int inf=0x3f3f3f3f;
const int mod=1e7+7;
int n,q,p,k,a[N],mx[N],l[N];
map<int,int>mp;
void solve()
cin>>n>>q;
int g=0,pos;
for(int i=1;i<=n;i++)
cin>>a[i];
if(a[i2021牛客暑期多校训练营1(部分补题)