今天的是欢乐场!大佬们看着我们受折磨而欢乐的欢乐场,,大佬说今天这场的题大多是经典题改编的,感觉很有意思,很多能看的题,,赶脚这套题可以好好研究研究,都比较经典。、
我们今天就A了一个题E,用的概率的知识点的思想。
E、Music Game
题意:n个位置,点或不点(1 or 0),每种情况没有连续x个位置都点了,即得价值X^m,求所有的期望
思路:概率上,其期望是概率*对应价值之和,本题可以得出对于所有情况,
对于每个区间【l,r】考虑,若区间[l,r]内均为1,且l-1,r+1为0,所有包含此区间情况的情况,都有通项((1-P(l-1))*P(l)*……*P(r)*(1-P(r+1)))*((r-l+1)^m),所以可提取出来,剩下的部分任意排列都符合,概率为1,所以整体的期望就是所有区间符合只此区间连续的期望和,,然后取逆元直接再输入P后直接处理就可,,
感想:简直要被这个题气死,做的时候预处理了很多,最后都没用上,,下面代码是删除无用的后,,再就是中间一直调不出来!,尝试输出又因为受逆元影响而无法辨别!!!然后因为自己粗心,将F【1】(表意:1^m,)写成了m~!!!!!真的是要剁手的节奏!!磨蹭了巨多时间!!!全因为这个1!!!这个粗心真的是要不得哇!!!!太坑了!
代码:
#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define INV 570000004
long long sum[1005],n,m,F[1005],P[1005],ga[1005][1005];
long long AA(long long a,long long b)
{
if(b==1) return a%mod;
if(b%2) return (AA((a*a)%mod,b/2)%mod*a)%mod;
else return AA((a*a)%mod,b/2)%mod;
}
int main()
{
scanf("%lld%lld",&n,&m);
F[1]=1;
for(int i=2;i<=n;i++)
{
F[i]=AA(i,m);
F[i]%=mod;
}
for(int i=1;i<=n;i++)scanf("%lld",&P[i]),P[i]=(P[i]*INV)%mod,ga[i][i]=P[i];;
long long r,ans=0,z;
for(int l=2;l<=n;l++)
{
for(int i=1;i+l-1<=n;i++)
{
r=l+i-1;
ga[i][r]=ga[i][r-1]*ga[r][r];
ga[i][r]%=mod;
}
}
for(int l=1;l<=n;l++)
for(int i=1;i+l-1<=n;i++)
{
r=l+i-1;
if(i-1>=1) z=(1-P[i-1]+mod)%mod;
else z=1;
if(r+1<=n) z*=(1-P[r+1]+mod)%mod;
else z*=1;
z%=mod;
ans+=((((ga[i][r]*z)%mod)*F[l])%mod)%mod;
ans%=mod;
}
printf("%lld\n",ans);
}
F、Typing practice
题意:给n个固定串,输入一系列操作,求每次后缀距离固定串的最小距离
思路:晚上看的直播,大佬说是数据出问题了,本来想将kmp,拓展kmp,AC自动机等全部卡掉的,但是数据没卡掉~,正解是trie图。。两眼一抹黑,,完全状况外,,但是比赛的时候这些方法都能过,,我们想的也是kmp,,但是没有调出来,,等着还是看看正解吧
代码:(PS:自己做的KMP的方法的,trie图的因为没学过,就看了看知识点,了解了一下,,也不做了,反正这个题的数据能过~trie图的就跟这个代码差个常数~)
#include<bits/stdc++.h>
using namespace std;
int nextt[5][100005],ans[100005],len[5];
void getFail(char *P,int *f)//P模板串,f是next数组
{
f[1]=f[0]=0;
int m=strlen(P);
for(int i=1,j;i<m;i++)
{
j=f[i];
while(j&&P[i]!=P[j])
j=f[j];
f[i+1]=P[i]==P[j]?j+1:0;
}
for(int i=1;i<m;i++)
if(P[i+1]==P[f[i+1]])
f[i+1]=f[f[i+1]];
return;
}
/*void find(char *T,char *P,int *f)//P模板串
{
int n=strlen(T);
int m=strlen(P);
int j=0;
for(int i=0;i<n;i++)
{
while(j && T[i]!=P[j]) j=f[j];
if(T[i]==P[j]) j++;
if(j==m) cnt++;//i-m+1: 下标从0开始,能够匹配的初始位置。
}
}*/
char ch[5][100005],chh[100005];
int j[5];
int main()
{
int n;
memset(ans,0x3f3f3f3f,sizeof(ans));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",ch[i]);
len[i]=strlen(ch[i]);
ans[0]=min(ans[0],len[i]);
getFail(ch[i],nextt[i]);
}
scanf("%s",chh);
printf("%d\n",ans[0]);
int tt=0,p[5][100005];
for(int i=0;i<strlen(chh);i++)
{
if(chh[i]!='-')
{
for(int l=1;l<=n;l++)
{
while(j[l] && chh[i]!=ch[l][j[l]]) j[l]=nextt[l][j[l]];
if(chh[i]==ch[l][j[l]]) j[l]++;
//cout<<l<<" "<<j[l]<<endl;
p[l][tt]=j[l];
ans[i]=min(ans[i],len[l]-j[l]);
//if(j[l]==m) cnt++;//i-m+1: 下标从0开始,能够匹配的初始位置。
}
tt++;
}
else
{
tt--;
for(int l=1;l<=n;l++)
{
j[l]=p[l][tt-1];
ans[i]=min(ans[i],len[l]-j[l]);
}
}
printf("%d\n",ans[i]);
}
}
下面是AC自动机 的代码,是很优化的O(n*L+m)的复杂度,跟trie图的复杂度一样,偷的别人的~但是据说思路很好,但是我没有学过这些东西~看不太懂,暂时不看,以后如果还记得的话再看~
//AC自动机
//查询模式串出现次数
#include <bits/stdc++.h>
using namespace std;
queue<int>que;
int ans[100003];
vector<int>g[100003];
struct Trie{
int ch[100003][26];
int fail[100003];
int end[100003];
int sz;
int newnode(){
for(int i=0;i<26;i++)ch[sz][i]=-1;
end[sz]=0;
return sz++;
}
void init(){
memset(end,0,sizeof(end));
sz=0;
newnode();
}
int idx(char c){
return c-'a';
}
void insert(char s[]){
int len=strlen(s);
int u=0;
for(int i=0;i<len;i++){
int c=idx(s[i]);
if(ch[u][c]==-1){
ch[u][c]=newnode();
}
u=ch[u][c];
}
end[u]=1;
//que.push(u);
//ans[u]=1;
}
void build(){
queue<int>q;
fail[0]=0;
for(int i=0;i<26;i++){
if(ch[0][i]==-1)ch[0][i]=0;
else {
fail[ch[0][i]]=0;
q.push(ch[0][i]);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<26;i++){
if(ch[u][i]==-1){
ch[u][i]=ch[fail[u]][i];
}
else {
fail[ch[u][i]]=ch[fail[u]][i];
q.push(ch[u][i]);
}
}
}
for(int i=0;i<sz;i++){
if(end[fail[i]])end[i]=1;
//cout<<i<<' '<<fail[i]<<' '<<end[i]<<endl;
if(end[i]){
que.push(i);
ans[i]=1;
}
}
}
void buildr(){
for(int i=0;i<sz;i++){
for(int j=0;j<26;j++){
g[ch[i][j]].push_back(i);
}
}
}
};
Trie T;
char s[100003];
int rec[100003];
int len=0;
int main(){
while(!que.empty())que.pop();
T.init();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s);
T.insert(s);
}
T.build();
T.buildr();
while(!que.empty()){
int u=que.front();
que.pop();
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(ans[v])continue;
ans[v]=ans[u]+1;
que.push(v);
}
}
scanf("%s",s);
printf("%d\n",ans[rec[len]]-1);
for(int i=0;s[i];i++){
if(s[i]=='-'){
if(len){
len--;
}
printf("%d\n",ans[rec[len]]-1);
}
else {
int c=s[i]-'a';
int v=T.ch[rec[len]][c];
rec[++len]=v;
printf("%d\n",ans[rec[len]]-1);
}
//cout<<rec[len]<<endl;
}
}
8
H、Prefix Sum
题意:给定n,m,k,两种操作:
1 x y:a[0][x]+=y;
2 x : cout<<a[k][x]<<endl;
a[i][1] = a[i-1][1] and a[i][j] = a[i][j-1] + a[i-1][j] (j >= 2)
思路:据大佬讲,推出公式,,然后两种暴力结合,,构成m√n的复杂度。。
/*但是比赛的时候只推出公式。,,没想到为什么要化成更小的,还可能出现负数。。。有点惊呆,,明天在看,,*/
今天看了一下题解,真是优秀!!比赛时我们思路是对的,也一直在想办法维护组合数的和,当然无果~~完全没想到将组合数拆分出来维护、、然后代码也就粘别人的了,,树状数组不想敲了!
代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-10;
const int maxn = 1e5 + 7;
#define REP(i, j, k) for(int i = j;i < k; ++i)
#define PER(i, j, k) for(int i = k - 1;i >= j; --i)
int n, m, k;
ll tr[105][maxn], frac[maxn], i_frac[maxn], inv[105];
void add(int id, int x, ll val)
{
while(x <= n)
{
tr[id][x] = (tr[id][x] + val) % mod;
x += (x & -x);
}
}
ll ask(int id, int x)
{
ll res = 0;
while(x > 0)
{
res = (res + tr[id][x]) % mod;
x -= (x & -x);
}
return res;
}
void init()
{
inv[1] = 1;
REP(i, 2, 105) inv[i] = inv[mod % i] * (mod - mod / i) % mod;
}
int main()
{
#ifdef DEBUG
freopen("input.txt", "r", stdin);
#endif // DEBUG
scanf("%d %d %d", &n, &m, &k);
k--;
init();
while(m--)
{
int op, x, y;
scanf("%d %d", &op, &x);
if(op == 0)
{
scanf("%d", &y);
ll u = 1;
REP(j, 0, k + 1)
{
add(j, x, u * y % mod);
u = u * (k - x - j) % mod * inv[j + 1] % mod;
}
}
else
{
ll ans = 0;
ll u = 1;
REP(j, 0, k + 1)
{
ans = (ans + u * ask(k - j, x) % mod) % mod;
u = u * (x - j) % mod * inv[j + 1] % mod;
}
printf("%lld\n", (ans + mod) % mod);
}
}
return 0;
}