C.Sum of Suffix Sums
题意:
一个初始为空的非负整数序列,
q
q
q 次操作
每次操作移除末尾的
t
t
t个整数,然后在末尾加入一个整数
v
v
v
每次操作后输出当前序列所有后缀和的总和
题解:
后缀和的总和,就是第
i
i
i位的数要加上
i
i
i遍,所有就是求
i
∗
a
[
i
]
i*a[i]
i∗a[i]的后缀和,每次把后
t
t
t个数删掉
代码:
#include<bits/stdc++.h>
#define int long long
#define rep(i,x,y) for(i=x;i<=y;i++)
using namespace std;
const int N=1e6+6;
const int mod=1e9+7;
int a[N],t=1;
void solve()
{
int n,k;
cin>>n>>k;
t-=n;
a[t]=k*t;
t++;
a[t-1]=(a[t-2]+a[t-1])%mod;
cout<<a[t-1]<<'\n';
}
signed main()
{
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
H.World Finals
题意:
有两次比赛,lzr010506知道自己在每次每个人的解题数和罚时,如果有人可以参加两次,可以随意安排,问lzr010506能取得的最佳成绩。
题解:
假设lzr010506参加第一次比赛,成绩比lzr010506好且可以参加第二次比赛的人安排去第二次比赛,假设lzr010506参加第二次比赛,同理。
代码:
#include<bits/stdc++.h>
#define int long long
using ll = long long;
using PII = std::array<int,2>;
using namespace std;
const ll INF = 2E18+10;
#ifdef __clang__
template<typename T>
inline int my_lg(T n) {
return (n > 0) ? static_cast<int>(log2(n)) : -1;
}
#define __lg my_lg
#define __gcd gcd
#endif
#ifndef ONLINE_JUDGE
#include "_debug.h"
#define EL std::cout<<"\n";
#define COUT(ITEM) std::cout<<#ITEM<<"="<<ITEM<<'\n';
#define CERR(ITEM) std::cerr<<#ITEM<<"="<<ITEM<<'\n';
#endif
// struct cmp{bool operator()(const int & x, const int &y) const{ return x<y; }};
const int N = 2E6 + 10;
void SINGLE_TEST()
{
int n,m;
cin>>n;
map<string,PII> a,b;
int ans=INF;
vector<string> s,w;
vector<int> s1,s2,w1,w2;
int t1,t2;
int z1,z2;
map<string,bool> vis1,vis2;
for(int i=1;i<=n;i++){
string ss;cin>>ss;
int ss1,ss2;
cin>>ss1>>ss2;
s.push_back(ss);
s1.push_back(ss1);
s2.push_back(ss2);
if(ss=="lzr010506"){
t1=ss1;
t2=ss2;
}
vis1[ss]=true;
}
cin>>m;
for(int i=1;i<=m;i++){
string ss;cin>>ss;
int ss1,ss2;
cin>>ss1>>ss2;
w.push_back(ss);
w1.push_back(ss1);
w2.push_back(ss2);
if(ss=="lzr010506"){
z1=ss1;
z2=ss2;
}
vis2[ss]=true;
}
int p1=0,p2=0;
for(int i=0;i<n;i++){
if(s[i]=="lzr010506") continue;
if(s1[i]>t1 || s1[i]==t1 && s2[i]<t2){
p1++;
if(vis2[s[i]]){
p1--;
}
}
}
for(int i=0;i<m;i++){
if(w[i]=="lzr010506") continue;
if(w1[i]>z1 || w1[i]==z1 && w2[i]<z2){
p2++;
if(vis1[w[i]]){
p2--;
}
}
}
cout<<min(p1,p2)+1<<"\n";
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
int SAMPLES = 1;
// cin>>SAMPLES;
while(SAMPLES--) SINGLE_TEST();
}
A.A Bit Common
题意:
构造一个序列,每个元素小于
2
m
2^m
2m,要求存在一个子序列的AND的和为
1
1
1,问有多少种可能性,答案对
q
q
q取模
题解:
我们只需要关注其二进制数
AND和为
1
1
1的话,就是第一位都是
1
1
1,其余位数都是0。我们把n个数,m位看成一个矩阵。例如
n
=
3
,
m
=
4
n=3,m=4
n=3,m=4时
0100
0100
0100
1011
1011
1011
0101
0101
0101
就是一个
3
×
4
3 \times 4
3×4的矩阵
要求存在子序列的AND和为
1
1
1,我们就遍历一遍最后一位是1的个数有
k
k
k个,在n个数的排列有
C
n
k
C_n^k
Cnk的可能性,求组合数因为模
q
q
q不确定,不能使用逆元,我们使用杨辉三角求组合数。
在k个数中,不能有一列全是1,那么这一列的可能性就是
2
k
−
1
2^k-1
2k−1(减
1
1
1是k位数全是1的可能性),去掉最后一位,共有
(
2
k
−
1
)
m
−
1
(2^k-1)^{m-1}
(2k−1)m−1的可能性
最后答案就是
C
n
k
C_n^k
Cnk
2
(
n
−
k
)
(
m
−
1
)
(
2
k
−
1
)
m
−
1
2^{(n-k)(m-1)}(2^k-1)^{m-1}
2(n−k)(m−1)(2k−1)m−1
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5000+6;
int memo[N][N];
int mod;
//杨辉三角
void init() {
for (int i = 1; i < N; i++) {
memo[1][i] = i % mod;
}
for (int i = 2; i < N; i++) {
for (int j = i; j < N; j++) {
memo[i][j] = (memo[i - 1][j - 1] + memo[i][j - 1]) % mod;
}
}
}
int C(int x, int y) {
if (x > y) {
return 0;
}
return memo[x][y] % mod;
}
//快速取模
int ksm(int a, int k) {
int res = 1;
while (k) {
if (k & 1) {
res = (res * a) % mod;
}
a = (a * a) % mod;
k >>= 1;
}
return res;
}
signed main()
{
int n, m;
cin >> n >> m >> mod;
init();
int ans = 0;
for (int i = 1; i <= n; i++) {
ans += C(i, n) * ksm(ksm(2, m - 1), n - i) % mod * ksm(ksm(2, i) - 1, m - 1) % mod;
ans %= mod;
}
cout<<ans<<'\n';
}
B.A Bit More Common
题意:
构造一个序列,每个元素小于 2 m 2^m 2m,要求存在两个不同的子序列的AND的和为 1 1 1,问有多少种可能性,答案对 q q q取模。
题解:
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5000+6;
int memo[N][N];
int dp[N][N],b[N];
int mod;
//杨辉三角
void init() {
for (int i = 1; i < N; i++) {
memo[1][i] = i % mod;
}
for (int i = 2; i < N; i++) {
for (int j = i; j < N; j++) {
memo[i][j] = (memo[i - 1][j - 1] + memo[i][j - 1]) % mod;
}
}
}
int C(int x, int y) {
if (x > y) {
return 0;
}
return memo[x][y] % mod;
}
//快速取模
int ksm(int a, int k) {
int res = 1;
while (k) {
if (k & 1) {
res = (res * a) % mod;
}
a = (a * a) % mod;
k >>= 1;
}
return res;
}
signed main()
{
int n, m;
cin >> n >> m >> mod;
init();
dp[0][0]=1;
int cnt1=0;
int ans = 0;
for (int i = 1; i <= n; i++) {
b[i] = ksm(2, n - i);
b[i] = ksm(b[i], m - 1);
ans += C(i, n) * b[i] % mod * ksm((ksm(2, i) - 1+mod)%mod, m - 1) % mod;
if(i==1)cnt1=ans%mod;
ans %= mod;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m - 1; j++)
{
dp[i][j] = i * (dp[i - 1][j - 1] + dp[i][j - 1]) % mod;
}
}
int cnt=0;
for (int i = 2; i <= n; i++)
{
int qk = ksm(2, i);
int op = (qk-i-1+mod)%mod;
int res = 1;
for (int j=m-1;j>=i;j--)
{
cnt = (cnt + C(i,n) * b[i] % mod * dp[i][j] % mod * res % mod * C(j,m-1)%mod) % mod;
res = res * op % mod;
}
}
// cout<<ans<<' '<<cnt<<' '<<cnt1<<'\n';
cout<<(ans-cnt-cnt1+2*mod)%mod<<'\n';
}
做出来继续更新。