2024“钉耙编程”中国大学生算法设计超级联赛(1)(B,H,A)

B. 星星

1.1翻译

小 A 有 n 次获得星星的机会。
在第i次机会里他有如下的 5 种选择(他必须做出恰好一种选择):
- 跳过这一轮。
- ai 的代价获得 11 颗星星。
- bi的代价获得 22 颗星星。
- ci 的代价获得 33 颗星星。
- di 的代价获得 44 颗星星。
他想要获得恰好 k 颗星星,请你帮他计算这个最小值。

1.2思路

经典背包dp

#include <vector>
#include <algorithm>
#include <iostream>
#define endl '\n'
#define int long long
using namespace std;

typedef pair<int,int> PII;

const int N = 300010, M = 600020; 



void solve()
{
    int n;
    cin >> n;
    int k;
    cin >> k;
    std::vector<int> av(n + 10);
    std::vector<int> bv(n + 10);
    std::vector<int> cv(n + 10);
    std::vector<int> dv(n + 10);
    std::vector<int> dp(k + 10,1e18 + 10);
    dp[0] = 0;
    for(int i = 1; i <= n; i ++)
    {
        int a,b,c,d;
        cin >> a >> b >> c >> d;
        av[i] = a;
        bv[i] = b;
        cv[i] = c;
        dv[i] = d;
        for(int j = min(4 * i,k); j >= 0; j --)
        {
            if(j >= 1) dp[j] = min(dp[j],dp[j - 1] + av[i]);
            if(j >= 2) dp[j] = min(dp[j],dp[j - 2] + bv[i]);
            if(j >= 3) dp[j] = min(dp[j],dp[j - 3] + cv[i]);
            if(j >= 4) dp[j] = min(dp[j],dp[j - 4] + dv[i]);
        }
    }
    cout << dp[k] << endl;
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int tt;
    cin >> tt;
    //tt = 1;
    while(tt --)
    {
        solve();
    }   
}

H. 位运算

2.1翻译

现在,对于一个在 [0,2k) 中的整数 n,小丁想要知道,有多少组也在[0,2k) 中的整数 a,b,c,d满足:

(((a & b) ^ c) | d) = n

2.2思路

位运算都是针对每一位,按位枚举,每一位满足的情况数量相乘就是所有方案数。

#include <vector>
#include <algorithm>
#include <iostream>
#define endl '\n'
#define int long long
using namespace std;

typedef pair<int,int> PII;

const int N = 300010, M = 600020; 



void solve()
{
    int n;
    cin >> n;
    int k;
    cin >> k;
    int ans = 1;
    for(int i = 0 ; i <= k - 1; i ++)//枚举每一位
    {
        int cnt = 0;
        int w = n >> i & 1;
        for(int a = 0; a < 2; a ++)
        {
            for(int b = 0; b < 2; b ++)
            {
                for(int c = 0; c < 2; c ++)
                {
                    for(int d = 0; d < 2; d ++)
                    {
                        if((((a & b) ^ c )| d) == w)
                        {
                            cnt ++;
                        }
                    }
                }
            }
        }
        ans *= cnt;
    }
    cout << ans << endl;
    
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int tt;
    cin >> tt;
    //tt = 1;
    while(tt --)
    {
        solve();
    }   
}

A. 循环位移

2.1翻译

2024“钉耙编程”中国大学生算法设计超级联赛(1) - Virtual Judge (vjudge.net.cn)

2.2思路

预处理a的所有循环串(在字符串a后接上a计算比较方便),枚举b的所有长度为n的字串,进行哈希

#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <set>
#define endl '\n'
using namespace std;

typedef pair<int,int> PII;

const int N = 31; 
typedef unsigned long long ull;
typedef long long ll;

ll Base1 = 29;
ll Base2 = 131;
ll MOD1 = 1e9 + 7;
ll MOD2 = 1e9 + 9;
const ll MAXN = 3e6 + 10;
string s1;

string s2;


ll h11[MAXN],h12[MAXN],p1[MAXN],p2[MAXN];
ll h21[MAXN],h22[MAXN];

set<pair<ll,ll>>yes;

void distinctEchoSubstrings() 
{
    p1[0] = 1, p2[0] = 1;
    for(int i = 1;i < s1.size();i++)
    {
        h11[i] = (h11[i - 1]*Base1 + (s1[i] - 'a' + 1)) % MOD1;
        h12[i] = (h12[i - 1]*Base2 + (s1[i] - 'a' + 1)) % MOD2;
    }
    for(int i = 1;i < s2.size();i++)
    {
        h21[i] = (h21[i - 1]*Base1 + (s2[i] - 'a' + 1)) % MOD1;
        h22[i] = (h22[i - 1]*Base2 + (s2[i] - 'a' + 1)) % MOD2;
    }
    for(int i = 1;i <= max(s1.size(),s2.size());i++)
    {
        p1[i] = (p1[i-1]*Base1) % MOD1;
        p2[i] = (p2[i-1]*Base2) % MOD2;
    }
}

int gethash11(ll l, ll r)
{
    ll now_has11 = ((h11[r] - h11[l - 1] * p1[r - l + 1] % MOD1) + MOD1) % MOD1;
    return now_has11;
}
int gethash12(ll l, ll r)
{
    ll now_has12 = ((h12[r] - h12[l - 1] * p2[r - l + 1] % MOD2) + MOD2) % MOD2;
    return now_has12;
}
int gethash21(ll l, ll r)
{
    ll now_has21 = ((h21[r] - h21[l - 1] * p1[r - l + 1] % MOD1) + MOD1) % MOD1;
    return now_has21;
}
int gethash22(ll l, ll r)
{
    ll now_has22 = ((h22[r] - h22[l - 1] * p2[r - l + 1] % MOD2) + MOD2) % MOD2;
    return now_has22;
}


void solve()
{
    cin >> s1;
    cin >> s2;
    int ans = 0;
    int len = s1.size();
    s1 = ' ' + s1 + s1;
    s2 = ' ' + s2;
    distinctEchoSubstrings();
    for(int i = 1;i <= len; i ++)
    {
        int l = i + len - 1;
        yes.insert({gethash11(i,l),gethash12(i,l)});
    }
    cout << endl;
    for(int i = 1; ;i ++)
    {
        int l = i + len - 1;
        if(l > s2.size() - 1) break;
        if(yes.find({gethash21(i,l),gethash22(i,l)}) != yes.end())
        {
            ans ++;
        }
    }
    cout << ans << endl;

}   

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int tt;
    cin >> tt;
    //tt = 1;
    while(tt --)
    {
        solve();
    }   
}

 L 并

2.1翻译

2024“钉耙编程”中国大学生算法设计超级联赛(1) - Virtual Judge (vjudge.net.cn)

2.2思路

离线差分做法,将给出的点进行离散化,再差分处理每一个面积为1的正方形被覆盖的次数,存再sum中,每一个这样的正方形贡献t的期望可以在随机选k个矩形时,可以通过O(n)的方法算出

{\sum_{t = 1}^{n}}^{}(C(n,k) - C(n - t,k))*sumt即先从n个里随意选k个,在从不包含这t个覆盖的矩形里选k个,相减就是一定可以选择覆盖t面积的方案数,每一个面积为1的,覆盖次数为t小正方形的方案数都是这么多,所以再乘上覆盖次数为t的小方格的数量即可

#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cstdio>
#include<algorithm>
inline int inc(int x,int v,int mod){x+=v;return x>=mod?x-mod:x;}//代替取模+
#define endl '\n'

using namespace std;

typedef pair<int,int> PII;
typedef long long LL;

const int mod = 998244353;
const int N = 4e3 + 10;

std::vector<int>arr1;
std::vector<int>arr2;

int qmi(int a, int k, int p)
{
    int res = 1;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9')
        x=x*10+ch-'0',ch=getchar();
    return x*f;
}
#define rep(i,a,b) for(int i=(a);i<=(b);++i)

int b[N][N];

struct Node
{
    int x1,y1,x2,y2;
}point[N];

int sum[N];

int C[N][N];
void solve()
{
    int n;
    n = read();
    arr1.push_back(-1);
    arr2.push_back(-1);
    C[0][0]=1;
    rep(i,1,n){
        C[i][0]=C[i][i]=1;
        rep(j,1,i-1)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
    
    for(int i = 1; i <= n;  ++i)
    {
        int a,b,c,d;
        a = read();
        b = read();
        c = read();
        d = read();
        arr1.push_back(a);
        arr2.push_back(b);
        arr1.push_back(c);
        arr2.push_back(d);
        point[i] = {a,b,c,d};
    }
    
    stable_sort(arr1.begin(),arr1.end());
    stable_sort(arr2.begin(),arr2.end());
    arr1.erase(unique(arr1.begin(),arr1.end()),arr1.end());
    arr2.erase(unique(arr2.begin(),arr2.end()),arr2.end());


    for(int i = 1; i <= n; ++i)
    {
        int x1 = lower_bound(arr1.begin(), arr1.end(), point[i].x1) - arr1.begin();
        int y1 = lower_bound(arr2.begin(), arr2.end(), point[i].y1) - arr2.begin();
        int x2 = lower_bound(arr1.begin(), arr1.end(), point[i].x2) - arr1.begin();
        int y2 = lower_bound(arr2.begin(), arr2.end(), point[i].y2) - arr2.begin();
        b[x1][y1] += 1;
        b[x2][y1] -= 1;
        b[x1][y2] -= 1;
        b[x2][y2] += 1;
    }
    
    int ux = arr1.size();
    int uy = arr2.size();

    for(int i = 1; i <= ux - 1; ++i)
    {
        for(int j = 1; j <= uy - 1; ++j)
        {
            b[i][j] += b[i-1][j] + b[i][j-1] - b[i-1][j-1];
            if(b[i][j] >= 1)
            {
                int op = 1ll * (arr1[i + 1]-arr1[i]) * (arr2[j + 1]-arr2[j])%mod;
                sum[b[i][j]] += op;
                sum[b[i][j]] %= mod;   
            }
        }
    }
    for(int i = 1; i <= n; ++i)
    {
        int ans = 0;
        int tx = C[n][i];
        for(int k = 1; k <= n; ++k)//枚举覆盖次数
        {
            int u = tx - C[n - k][i];
            u = inc(u,mod,mod);
            //共有u种方案,可以使得覆盖次数为k的矩形,提供1的面积
            ans += (1ll * sum[k] * u % mod);
            ans %= mod;
        }
        cout << 1ll * ans * qmi(tx,mod - 2,mod)%mod << endl;
    }
}

int main()
{
    int tt;
    //cin >> tt;
    tt = 1;
    while(tt --)
    {
        solve();
    }   
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值