ABC三题题解。
A:牛牛选物
状态压缩枚举所有情况即可。
最多1<<20 1e6

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 返回总体积为V若干物品的最大总重量,如果g存在选择若干物品总体积为V的情况,返回-1
     * @param v int整型vector 
     * @param g int整型vector 
     * @param V int整型 
     * @return int整型
     */
    int Maximumweight(vector<int>& v, vector<int>& g, int V) {
        // write code here、
        int n=v.size(),mx=-1;
        for(int i=0;i<(1<<n);i++){
            int tv=0,tg=0;
            for(int j=0;j<n;j++){
                if((i>>j)&1){
                    tv+=v[j];
                    tg+=g[j];
                }
            }
            if(tv==V)mx=max(mx,tg);
        }
        return mx;
    }

};

B:牛牛与字符串2
KMP nxt数组裸题,KMP还是要熟练掌握的呀,基础知识点。

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 给定一个字符串s,返回具有相同前缀后缀的子串的第二大长度,反之,返回-1即可。
     * @param s string字符串 代表题意中的字符串s
     * @return int整型
     */
    char a[1000007];
    int Next[1000007],cnt;
    void getNext()
    {
        Next[0]=-1;
        int n=strlen(a+1);
        for(int i=2,j=0;i<=n;i++)
        {
            while(j>0&&a[i]!=a[j+1])j=Next[j];
            if(a[i]==a[j+1])j++;
            Next[i]=j;
        }
    }
    int solve(string s) {
        // write code here
        int n=s.length();
        for(int i=1;i<=n;i++)a[i]=s[i-1];
        getNext();
        if(Next[n]==0)return -1;
        return Next[n];
    }
};

C:
最短路+对数优化乘法
路径边权积显然满足动态规划的性质,可以最短路做。
但这一题的瓶颈在于最短路的时候乘***爆ll。
仔细观察题目全是乘法,于是想到可以用对数优化。
log(a * b) = log(a) + log(b);
另外维护一个数组f表示正常取模的最短路,更新用对数优化的实际最短路e,最后输出时用取模的最短路f。
不过这题没必要用堆优化,优化反而最坏情况下多个log。
直接n^2松弛更新即可(但我代码写的dij,懒得改了。。。反正就多个log n = 5)。

注意:刚开始算组合数的时候就会爆ll,在求组合数的时候就要注意维护对数数组进行优化!

typedef long long ll;
const int M = 2e6+7;
const int mod =1e9+7;
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param n int整型 有n个城市
     * @param m int整型 有m条路径
     * @param s int整型 起始城市坐标
     * @param t int整型 终点城市坐标
     * @param edge int整型vector<vector<>> 边的格式如下:[[u1,v1,a1,b1],[u2,v2,a2,b2],...]
     * @return int整型
     */

   int head[M],cnt=1;
    void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
    struct EDGE{int to,nxt,w;double e;}ee[M*2];
    void add(int x,int y,int w,double e){ee[++cnt].nxt=head[x],ee[cnt].e=e,ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
    bool vs[M];
    ll fac[1100],f[1100];
    double fae[1100],d[M];
    ll qpow(ll a,ll b){
        ll ans=1;
        while(b){
            if(b&1)ans=ans*a%mod;
            a=a*a%mod;
            b/=2;
        }
        return ans;
    }
    ll C(int n,int m){
        return fac[n]*qpow(fac[n-m],mod-2)%mod*qpow(fac[m],mod-2)%mod;
    }
    ll CE(int n,int m){
        return fae[n]-fae[n-m]-fae[m];
    }
    priority_queue<pair<double,int> ,vector<pair<double,int> >,greater<pair<double,int> > >q;
    ll dij(int s,int t,int n){
        for(int i=1;i<=n;i++)d[i]=2e18+7,f[i]=1;
        memset(vs,0,sizeof(vs));
        d[s]=0;f[s]=1;
        q.push({d[s],s});
        while(!q.empty()){
            pair<double,int>  tp=q.top();q.pop();
            int u=tp.second ;
            if(vs[u])continue;
            vs[u]=1;
            for(int i=head[u];i;i=ee[i].nxt){
                int v=ee[i].to,w=ee[i].w;double e=ee[i].e;
                if(d[v]>d[u]+e)//1经过u再到v的距离小于 1直接到v的距离 则更新距离
                    f[v]=f[u]*w%mod,d[v]=d[u]+e,q.push({d[v],v});
            }
        }
        return f[t];
    }

    int minDist(int n, int m, int s, int t, vector<vector<int> >& edge) {
        // write code here
        memset(head,0,sizeof(head));memset(f,0,sizeof(f));
        cnt=1;fae[0]=0;fac[0]=1;
        for(int i=1;i<=1000;i++)fac[i]=fac[i-1]*i%mod,fae[i]=fae[i-1]+log(i);
        for(auto x:edge){
            ll w=C(x[2],x[3]);
            double e=CE(x[2],x[3]);
            add(x[0],x[1],w,e);
            add(x[1],x[0],w,e);
        }
        return dij(s,t,n);
    }
};