SMU Summer 2024 Contest Round 8

Hcode OnlineJudge

思路:由于 ,所以如果直接暴力dfs查找,也是不会超时的,一开始看成和不大于1e5,浪费了点时间

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long

int n,x;
int ans=0;
vector<vector<int>>a;
void dfs(int pos,int w){
    if(pos==n){
        if(w==x) ans++;
        return ;//别忘记return,我谢谢你
    }
    for(int u:a[pos]){
        if(w>x/u) continue;
        dfs(pos+1,w*u);
    }
}


signed main(){
    cin>>n>>x;
    a.resize(n);
    for(int i=0;i<n;i++){
        int t;
        cin>>t;
        a[i].resize(t);
        for(int j=0;j<=t-1;j++)cin>>a[i][j];
    }
    
    dfs(0,1);
    cout<<ans<<endl;
    return 0;
}

Hcode OnlineJudge

题解:,首先,如果我们把<=k改成=k,那么就变成了长度为M的数组中选择N个数相加为k的方案数,这里是做了一点更改,也就是最后再做一个前缀和与滚动数组。

动态转移方程:ndp[j]+=dp[j-p];
代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,k;

const long long mod=998244353;
void solve(){
    cin>>n>>m>>k;
    vector<int>dp(k+1);
    vector<int>ndp(k+1);
     // dp[i][j] 表示前 i 个数,和为 j 的方案数
    // dp[i][j] = dp[i - 1][k], k < j
    dp[0]=1;
    for(int i=1;i<=n;++i){
        for(int j=i;j<=min(k,i*m);++j){
            ndp[j]=0;
            for(int p=1;p<=m&&j-p>=i-1;++p){
                ndp[j]+=dp[j-p];
                ndp[j]%=mod;
            }


       }
       swap(dp,ndp);
    }
    int ans=0;
    for(int j=n;j<=min(n*m,k);j++){
        ans=(ans+dp[j])%mod;
    }
    cout<<ans<<endl;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;

    while(t--){
        solve();
    }
    return 0;
}


Hcode OnlineJudge

题解:每个位置各个数字等可能的情况:10^n

           不存在0和不存在9的情况:9^n

            0,9同时不存在的情况:8^n

            所以0,9,同时存在的情况有(10^n-(2*9^n-8^n))%mod,最后注意一下负数取余就行

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5, mod = 1e9 + 7;
int n;
int qm(int x,int p){
    int re=1;
    while(p){
        if(p&1) re=re*x%mod;
        x=x*x%mod;
        p>>=1;
    }
    return re;
}
signed main() {
    cin>>n;
    cout<<(qm(10,n)-(2*qm(9,n)-qm(8,n))%mod+mod)%mod;
    return 0;
}

Hcode OnlineJudge

题解:我们可以设置一个二维数组dp[N][10],dp[i][j]代表前i个操作产生结果为j的结果总数

动态转移方程就是 

            dp[i + 1][(j + a[i + 1]) % 10] = (dp[i][j] + dp[i + 1][(j + a[i + 1]) % 10]) % mod;
            dp[i + 1][(j * a[i + 1]) % 10] = (dp[i][j] + dp[i + 1][(j * a[i + 1]) % 10]) % mod;

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,k;
int dp[100010][10];
const long long mod=998244353;
void solve(){
    cin>>n;
    vector<int> a(n+10);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    memset(dp, 0, sizeof(dp));
    dp[1][a[1]] = 1;
    for (int i = 1; i <= n - 1; i++)
    {
        for (int j = 0; j <= 9; j++)
        {
            dp[i + 1][(j + a[i + 1]) % 10] = (dp[i][j] + dp[i + 1][(j + a[i + 1]) % 10]) % mod;
            dp[i + 1][(j * a[i + 1]) % 10] = (dp[i][j] + dp[i + 1][(j * a[i + 1]) % 10]) % mod;
        }
    }
    for (int k = 0; k < 10; k++)
    {
        cout << dp[n][k] % mod << endl;
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;

    while(t--){
        solve();
    }
    return 0;
}

Hcode OnlineJudge

题解:

首先分析一下,答案的区间。显然是[0,N]

所以如果每个元素的值不在这个区间内,那么它是不起作用的。

因此,第11个元素最多起作用n+1次,第22个元素n/2+1次,...,第N个元素2次。

本题的做法就是先找到每个元素起作用的区间[l,r],然后计算对应的值。设置M个vector,存储在每一次中出现的值。最后遍历一下即可。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200010;
int n, m;
int a[N];
vector<int> f[N];

int main()
{
    cin>>n>>m;
    for(int i = 1; i <= n; i ++) cin>>a[i];
    for(int i = 1; i <= n; i ++) {
        if(a[i] >= n) continue;
        int l,r;
        if(a[i]>=0) l=1;
        else l=(-a[i]-1)/i+1;
        r = min(m + 1, (n - a[i] - 1) / i + 1);
        for(int j = l; j < r; j ++) {
            f[j].push_back(a[i] + i * j);
        }
    }
    for(int i = 1; i <= m; i ++) {
        int x = 0;
        sort(f[i].begin(), f[i].end());
        f[i].erase(unique(f[i].begin(), f[i].end()), f[i].end());//去重
        if(!f[i].size()) {
            cout<<0<<endl;
            continue;
        }
        bool flag = false;
        for(auto p : f[i]) {
            if(p != x) {
                flag = true;
                cout<<x<<endl;
                break;
            }
            x ++;
        }
        if(!flag) cout<<x<<endl;
    }
    return 0;
}

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值