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)的方法算出
即先从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();
}
}