今天状态不好啊,净是犯小错误qwq

A.小A买彩票

一道签到题。

注意到,概率=不亏的方案数/总方案数

而,总方案数=(每次从1,2,3,4中选一个,选n次)

那么,我们只需要计算的就是不亏的方案数了。

我们注意到,n很小,而且,最多可以获得的也才元(先不考虑支付的元)

那么,这个明显可以使用dp统计方案数。

我们设dp[i][j],表示前i次抽奖中,不考虑支付的3*i元的情况下,获得j元的方案数。

那么我们只需要分当前中的是1元,2元,3元,4元四个情况考虑转移即可。

最后,我们直接统计获得的钱数不小于3*n的方案数之和即可。

复杂度:

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int dp[31][121];
signed main(){
    int n;
    scanf("%lld",&n);
    dp[0][0]=1;
    for(int i=1;i<=n;++i){
        for(int j=i;j<=i*4;++j){
            for(int k=1;k<=4;++k){
                if(j<k)break;
                dp[i][j]+=dp[i-1][j-k];
            }
        }
    }
    int tot=0;
    for(int i=3*n;i<=4*n;++i){
        tot+=dp[n][i];
    }
    int sum=pow(4,n);
    int D=__gcd(tot,sum);
    tot/=D,sum/=D;
    printf("%lld/%lld",tot,sum);
    return 0;
}

B.「金」点石成金

看到n这么小,而且每次的状态也就两种。。。直接爆搜即可。

需要注意的是,做减法的时候记得把差和0取最大值。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=16;
#define int long long
int a[N],b[N],c[N],d[N],ans,n;
inline int max(int x,int y){
    return x>y?x:y;
}
inline void dfs(int now,int l,int r){
    if(now==n+1){
        ans=max(ans,l*r);
        return;
    }
    dfs(now+1,l+c[now],max(0,r-d[now]));
    dfs(now+1,max(0,l-b[now]),r+a[now]);
}
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;++i){
        scanf("%lld%lld%lld%lld",&a[i],&b[i],&c[i],&d[i]);
    }
    dfs(1,0,0);
    printf("%lld",ans);
    return 0;
}

C.小阳的贝壳

这是个挺套路的题目,他的第二个询问其实就已经提醒你怎么做了。

我们用一颗线段树维护一个差分数组即可。

对于区间修改,我们直接改成做差分数组的两次单点修改即可

对于询问差的最大值,我们直接找到区间最大值即可

至于询问gcd,我们先求出现在第l个数的真实的值(做个前缀和就行了),然后和l+1-r的差分数组的gcd取gcd即可。

为啥正确呢?

因为,有如下定理:

[这个大家在学辗转相除或更相减损的应该都接触过]

(这个和最值的有点相似,这个的证法很多,个人推荐用分解质因数然后转化成区间最值的形式证明)

由第二个定理,我们不难得出:

然后由第一个定理,我们不难得出:

于是,我们直接求出这个东西就行了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
struct node{
    int w,g,s;
}t[N<<2];
int a[N];
inline int my_max(int x,int y){//绝对值最值
    return abs(x)>abs(y)?x:y;
}
inline void build(int now,int l,int r){
    if(l==r){
        t[now].w=t[now].g=t[now].s=(a[l]);
        return;
    }
    int mid=(l+r)>>1;
    build(now<<1,l,mid),build(now<<1|1,mid+1,r);
    t[now].w=my_max(t[now<<1].w,t[now<<1|1].w);
    t[now].g=__gcd(t[now<<1].g,t[now<<1|1].g);
    t[now].s=t[now<<1].s+t[now<<1|1].s;
}
inline void insert(int now,int l,int r,int x,int y){
    if(l==r){
        t[now].w=t[now].g=t[now].s=(t[now].w+y);
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid){
        insert(now<<1,l,mid,x,y);
    }else{
        insert(now<<1|1,mid+1,r,x,y);
    }
    t[now].w=my_max(t[now<<1].w,t[now<<1|1].w);
    t[now].g=__gcd(t[now<<1].g,t[now<<1|1].g);
    t[now].s=t[now<<1].s+t[now<<1|1].s;
}
inline int find1(int now,int l,int r,int lc,int rc){//区间绝对值最值
    if(lc<=l&&r<=rc){
        return t[now].w;
    }
    int mid=(l+r)>>1,res=0;
    if(lc<=mid){
        res=my_max(res,find1(now<<1,l,mid,lc,rc));
    }
    if(rc>mid){
        res=my_max(res,find1(now<<1|1,mid+1,r,lc,rc));
    }
    return res;
}
inline int find2(int now,int l,int r,int lc,int rc){//区间gcd
    if(lc<=l&&r<=rc){
        return t[now].g;
    }
    int mid=(l+r)>>1,res=0;
    if(lc<=mid){
        res=__gcd(res,find2(now<<1,l,mid,lc,rc));
    }
    if(rc>mid){
        res=__gcd(res,find2(now<<1|1,mid+1,r,lc,rc));
    }
    return res;
}
inline int find3(int now,int l,int r,int lc,int rc){//区间和
    if(lc<=l&&r<=rc){
        return t[now].s;
    }
    int mid=(l+r)>>1,res=0;
    if(lc<=mid){
        res=(res+find3(now<<1,l,mid,lc,rc));
    }
    if(rc>mid){
        res=(res+find3(now<<1|1,mid+1,r,lc,rc));
    }
    return res;
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
    }
    for(int i=n;i;--i){
        a[i]-=a[i-1];
    }
    build(1,1,n);
    while(m--){
        int opt,l,r;
        scanf("%d%d%d",&opt,&l,&r);
        if(opt==1){
            int x;
            scanf("%d",&x);
            insert(1,1,n,l,x);
            if(r<n){
                insert(1,1,n,r+1,-x);
            }
        }else if(opt==2){
            if(l==r){
                puts("0");
                continue;
            }
            printf("%d\n",abs(find1(1,1,n,l+1,r)));
        }else{
            if(l==r){
                printf("%d\n",find3(1,1,n,1,l));
            }else{
                printf("%d\n",abs(__gcd(find3(1,1,n,1,l),find2(1,1,n,l+1,r))));
            }
        }
    }
    return 0;
}

D.Forsaken喜欢字符串

读完题,我们发现,询问其实就是求,其余的字符串中,和当前字符串中所有长度为len的子串的匹配个数之和再乘len

注意到,n,q很大,所以我们肯定不能直接比较。

但是,我们发现k非常小。

于是,我们对所有的串求出他的所有子串,然后用一个map每个字符串的出现次数。

这样,在询问的时候,我们把第x个字符串的所有长度为y的子串处理出来,然后直接查询当前子串在map的出现次数就行了。

但是,因为子串不能和同一个字符串的子串匹配,所以,我们还要算出当前子串在第x个字符串的出现次数,然后答案减去这个出现次数即可(即,只和第x个字符串以外的字符串匹配)

(思路早想到了,但实现时换了好几种写法。。。今天真的状态布星啊qwq)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+1;
int n,k;
char s[N][6];
map<string,int>sp,ep;
inline string get_string(int id,int x,int y){
    string now="";
    for(int i=1;i<=y;++i){
        now+=s[id][x+i-1];
    }
    return now;
}
signed main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i){
        scanf("%s",s[i]+1);
        for(int j=1;j<=k;++j){
            for(int p=1;p<=k-j+1;++p){
                ++sp[get_string(i,p,j)];
            }
        }
    }
    int q;
    scanf("%d",&q);
    while(q--){
        int x,y;
        scanf("%d%d",&x,&y);
        long long ans=0;
        ep.clear();
        for(int i=1;i<=k-y+1;++i){
            ++ep[get_string(x,i,y)];
        }
        for(int i=1;i<=k-y+1;++i){
            string now=get_string(x,i,y);
            ans+=sp[now]-ep[now];
        }
        printf("%lld\n",ans*y);
    }
    return 0;
}

E.Board

见过这个题,原题不是加任意数而是加1,不过其实是一样的。。。

我们首先分析,设表示第i行加的数字之和,表示第i列加的数字之和,第i行第j列的数字为

那么,对于第i行第j列的数字,它现在的值即为

于是,我们设被隐藏的数字是第a行第b列的那个,那么它的值即为

我们想办法把这个和构造出来。

我们随便再找两个数字c,d(c,d<=n),使得c!=a,d!=b

那么,我们就有:

注意到,

而,又因为只有第a行第b列的值是不确定的,所以,这三个数字的值是确定的。

所以,我们直接输出这个式子的值就行了

代码:

#include<bits/stdc++.h>
using namespace std;
int a[1001][1001];
signed main(){
    int n,x,y;
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            scanf("%d",&a[i][j]);
            if(a[i][j]==-1){
                x=i,y=j;
            }
        }
    }
    int k=1,t=1;
    if(y==k)++k;
    if(x==t)++t;
    printf("%d",a[x][k]+a[t][y]-a[t][k]);
    return 0;
}