Codeforces场合集
Codeforces一些场次题解
Codeforce场合集
Codeforces Round 940 (Div. 2)
1957C 递推
/*
* @Author : Danc1ng
* @Date : 2024-05-07 13:47:32
* @FilePath : 1957C
* @Origin : https://codeforces.com/contest/1957/problem/C
* @Description:
* @Solution :
* 对于n*n的棋盘来说,如果棋子放在(x,x)位置,则剩下方案在(n-1)*(n-1)的棋盘里放置
* 如果放在(x,y)(x!=y),则剩下方案在(n-2)*(n-2)的棋盘里 考虑递推
*
* # # # #
* # # # #
* # # @ @
* # # @ @
* dp[i]可以由dp[i-1]和dp[i-2]递推过来
* dp[i-1]递推到dp[i]说明放置在对角线上,只有一种方案-->dp[i]+=dp[i-1]
* dp[i-2]递推到dp[i]说明放置点不在对角线上,
* 从dp[i]退化到dp[i-2]是放置在边界的不在对角线上的点,一共(i-2)*2个 -->dp[i]+=(i-1)*dp[i-2]*2;
* ==>dp[i]=dp[i-1]+(i-1)*dp[i-2]*2;
*
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 3e5 + 10 , INF = 2e9,mod=1e9+7;
int n,k;
int dp[N];
void init()
{
dp[0]=dp[1]=1;
for(int i=2;i<=3e5;i++)
{
dp[i]=(dp[i-1]%mod+(i-1)*dp[i-2]%mod*2)%mod;
}
}
void solve()
{
cin>>n>>k;
for(int i=0;i<k;i++)
{
int x,y;
cin>>x>>y;
if(x==y) n--;
else n-=2;
}
cout<<dp[n]<<endl;
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
init();
int T;
//T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
1957D 位运算
/*
* @Author : Danc1ng
* @Date : 2024-05-07 14:05:21
* @FilePath : 1957D
* @Origin :
* @Description:
* @Solution :
* 令s[i]表示1~i的前缀异或和则f(x,z)=s[z]^s[x-1];
* f(x,y)^f(y,z)>f(x,z)则表示 s[z]^s[x-1]^a[y]>s[z]^s[x-1];
* 设t=s[z]^s[x-1] ---> t^a[y]>t
* 对于a[y]中最高位的1来说,如果t对应位为1则t^a[y]变小(即使后面位置改变后为1),
* 所以要想变大对应位要为0
* 枚举这个a[y]然后记录方案数
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 2e5 + 10 , INF = 2e9;
int n;
int a[N],s[N];
int c[30][N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]^a[i];
//记录1~i中s[i]该位为1的s[x]的数量
for(int j=0;j<30;j++)
c[j][i]=c[j][i-1]+(s[i]>>j&1);
}
int ans=0;
//枚举a[y];
for(int i=1;i<=n;i++)
{
//找a[y]最高位的1
int k=29;
while(k>=0&&(a[i]>>k&1)==0) k--;
if(k==-1) continue;
/*
当前a[y]的最高位的1为k,要想t为0则s[z]和s[x-1]的k位要么都为1,要么都为0
z的范围位[i,n];x-1的范围位[1,i-1]
*/
ans+=(c[k][n]-c[k][i-1])*c[k][i-1];//i~n中k位为1的s[z]数量*(1~i-1)中k位为1的s[x-1]数量
ans+=(n-i+1-(c[k][n]-c[k][i-1]))*(i-c[k][i-1]);//总数量减1的数量就是0的数量
}
cout<<ans<<endl;
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;
//T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
1957E 数学 -威尔逊定理
/*
* @Author : Danc1ng
* @Date : 2024-05-07 15:00:18
* @FilePath : 1957E
* @Origin : https://codeforces.com/contest/1957/problem/E
* @Description:
* F(i,k)表示从i个数中选k个数的环排列数,给一个n求 Σ(i=1~n)Σ(j=1~i)(F(i,j)mod j)
* @Solution :
*
* n的环排列数为(n-1)!, n的排列数为n!,而1,2,3,..n和2,3,...,n,1是一个环排列,这样有n个 所以答案为 n!除以n=(n-1)!
* 那么对于F(i,j) mod j = C(i,j)*(j-1)! mod j= A(i,j)/A(j,j)*(j-1)!mod j=A(i,j)/j mod j;
* 由于分子是 j 个连续整数的乘积,因此至少有一个整数能被 j 整除
* i*(i-1)*(i-2)*....*(i-j+1)/j mod j= (j-1)!*(i/j) mod j;
* 在这里我们可以发现,j的所有适当因数都会出现在 (j−1)! 中,因此根据这一点我们可以知道, C(i,j)mod j =0
* 适用于除 j=4 之外的所有合数 j
* 威尔逊定理,我们知道当 j 是质数时,(j−1)! ≡−1 modj
。
*
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 1e6 + 10 , INF = 2e9,mod=1e9+7;
int n;
bool notPri[N];
int f[N];
void init()
{
for(int j=2;j<N;j++)
{
if(!notPri[j]||j==4)
{
for(int i=j;i<N;i+=j)
{
notPri[i]=true;
int d=i/j*(j==4?2:j-1)%j;
(f[i]+=d)%=mod;
if(i+j<N) (f[i+j]+=mod-d)%=mod;
}
}
}
for(int i=1;i<N;i++) (f[i]+=f[i-1])%=mod;
for(int i=1;i<N;i++) (f[i]+=f[i-1])%=mod;
}
void solve()
{
cin>>n;
cout<<f[n]<<endl;
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
init();
int T;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
Codeforces Round 941 (Div. 2)
1966D 构造
/*
* @Author : Danc1ng
* @Date : 2024-05-08 22:52:28
* @FilePath : 1966D
* @Origin : https://codeforces.com/contest/1966/problem/D
* @Description: 构造出一个长度不超过25的序列使子序列可以表示1~n中除k以外所有的数
* @Solution :
* 首先考虑如何表示1~n中所有数,用1,2,4,8,16...二进制即可
* 为了不表示k则我们可以对于1~k-1的数用1,2,4,8,16...来表示,
* 假设k的最高位为h,则将2^h替换为(k-1)-Σ(2^i)(0<=i<=h-1),则前h+1项可以表示出[1,k-1],
* 加入k+1,则可以表示[1,2k],再加入2k则可以表示[1,4k],再加入4k则可以表示[1,8k],...
* 但因为k不能表示所以3k无法表示
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 2e5 + 10 , INF = 2e9;
int n,k;
int a[N];
void solve()
{
cin>>n>>k;
int len=0,k1=k;
vector<int> ans;
if(k==1)
{
ans.push_back(3);
for(int i=1;i<=24;i++) ans.push_back(1<<i);
}
else
{
while(k1)
{
k1>>=1;
len++;
}
int res=1;
for(int i=1;i<len;i++)
{
ans.push_back(res);
res*=2;
}
ans.push_back(k-(1<<(len-1)));
ans.push_back(k+1);
ans.push_back(3*k);
res=2;
while(ans.size()<25)
{
ans.push_back(res*k);
res*=2;
}
}
cout<<25<<endl;
for(auto i:ans) cout<<i<<' ';
cout<<endl;
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;
//T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
Educational Codeforces Round 165 (Rated for Div. 2)
1969C DP
/*
* @Author : Danc1ng
* @Date : 2024-05-09 16:01:49
* @FilePath : 1969C
* @Origin : https://codeforces.com/contest/1969/problem/C
* @Description:
* 给一个长度为n的数组,每个可以选择数组的一个元素用它相邻的元素替代它,最多可以进行k次操作
* 问数组和的最小值是多少
* @Solution :
*
* 直接每次操作找差值最大的位置的思路是错误的,因为最小值传递后差值可能会更大更优
* 例如n=6,k=3, 4 1 2 4 4 3 --> 1 1 1 1 4 3 !-->1 1 1 2 4 3
* 因为k比较小 考虑dp
* dp[i][j]表示到i的时候用了j次操作的最小和
* dp[i][j]=min(dp[i-1][j]+a[i](不操作),dp[i-k-1][j-k]+min(a[i-k],a[i-k+1],...,a[i]))操作k次
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 3e5 + 10 , INF = 1e18;
int n,k;
int a[N];
void solve()
{
cin>>n>>k;
vector<vector<int>> dp(n+1,vector<int>(k+1,INF));
dp[0][0]=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
dp[i][0]=dp[i-1][0]+a[i];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=k;j++)
{
int res=a[i];
//该位置不操作
dp[i][j]=min(dp[i][j],dp[i-1][j]+res);
//枚举操作次数1~j
for(int l=1;l<=j&&l+1<=i;l++)
{
res=min(res,a[i-l]);
dp[i][j]=min(dp[i][j],dp[i-l-1][j-l]+(l+1)*res);
}
}
}
cout<<*min_element(dp[n].begin(),dp[n].end())<<endl;
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;
//T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
1969D 贪心
/*
* @Author : Danc1ng
* @Date : 2024-05-09 19:14:13
* @FilePath : 1969D
* @Origin : https://codeforces.com/contest/1969/problem/D
* @Description:
* 有n件商品,ai是alice购买i商品需要的价格,bi是bob购买i商品需要的价格
* alice选若干个商品,若商品数量<k则bob免费拿走所有商品,否则bob拿免费拿走alice购买的商品中k件
* 其他付费购买,alice的利润是bob购买的商品价格之和-alice购买的商品价格之和,alice希望利润最大化
* bob希望alice的利润最小化,求都采取最优行动下的alice的利润
* @Solution :
* 假设现在alice购买了若干物品那么bob会选择免费拿去价格大的前k个,
* 那么以bi升序排列,找一个分界点,则右侧有bob的免费的k个物品,
* 对于bob拿的免费的物品,alice一定是亏的,alice选择ai最小的k个则会亏得最少
* 对于分界点的左侧,只要bi>ai则有利润,直接购买
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 2e5 + 10 , INF = 2e9;
struct Node
{
int x,y;
}a[N];
int n,k;
int pre[N];
bool cmp(Node a,Node b)
{
return a.y<b.y;
}
void solve()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i].x;
}
for(int i=1;i<=n;i++)
{
cin>>a[i].y;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
pre[i]=pre[i-1]+max(0ll,a[i].y-a[i].x);
}
priority_queue<int> q;
int ans=0,sum=0;
for(int i=n;i>=1;i--)
{
if(q.size()>=k)
{
ans=max(ans,pre[i]-sum);
}
q.push(a[i].x);
sum+=a[i].x;
if(q.size()>k)
{
sum-=q.top();
q.pop();
}
}
cout<<ans<<endl;
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;
//T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
Codeforces Round 942 (Div. 2)
1972B- 博弈 找性质
/*
* @Author : Danc1ng
* @Date : 2024-05-10 15:37:55
* @FilePath : 1972B
* @Origin : https://codeforces.com/contest/1972/problem/B
* @Description:
* @Solution :
* 对于UUU,DUD,UUD,DUU四种情况来说,操作后U的数量改变为-3,+1,-1,-1,也就是说操作后U的数量的奇偶性会改变
* 因为最终面临U为0的时候会败,所以如果先手U的数量为奇数则会赢,因为操作后总会把U为偶数的局面留给后手,
* 而先手U的数量为偶数则会败,因为后手总会把U为偶数的局面留给自己
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 2e5 + 10 , INF = 2e9;
int n;
int a[N];
char c[N];
void solve()
{
cin>>n;
int cnt=0;
for(int i=0;i<n;i++)
{
cin>>c[i];
if(c[i]=='U') cnt++;
}
if(cnt&1) YES
else NO
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;
//T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
1972C-构造 二分
/*
* @Author : Danc1ng
* @Date : 2024-05-10 19:41:25
* @FilePath : 1969C
* @Origin : https://codeforces.com/contest/1972/problem/C
* @Description:
* 给一个长度为n的数组a,a[i]表示数字为i的牌有a[i]个,你可以再购买k张任意数字的牌,
* 然后给牌重新排列,重新排列的分数是长度为n的连续子数组中的全排列个数,最高得分是多少
* @Solution :
* 要解决 1.如何购买k张牌,2.如何排列
* 优先购买牌数少的数字的牌,由于k<=10^12,所以需要一次性知道最终最少的牌的数量,可以二分答案
* 如何排列, 像1 2 3 1 2 3 1 2 3--1 2 这样能最大化得分,假设1 2 各多一张,则可以放在后面
* 也就是说优先放牌数多的然后放牌数少的 再放多余的牌
* 答案就是1+(mi-1)*n+多出来的牌数 mi表示购买k张后最少的牌的数量
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 2e5 + 10 , INF = 2e9;
int n,k;
int a[N];
bool check(int mid)
{
int need=0;
for(int i=1;i<=n;i++)
if(a[i]<mid) need+=mid-a[i];
return need<=k;
}
void solve()
{
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
int l=1,r=2e12;
while(l<r)
{
int mid=(l+r+1)>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
int mi=r;
for(int i=1;i<=n;i++)
{
if(a[i]<mi)
{
k-=mi-a[i];
a[i]=mi;
}
}
int num=0;
for(int i=1;i<=n;i++)
{
if(a[i]==mi&&k) a[i]++,k--;
if(a[i]>mi) num++;
}
cout<<1+(mi-1)*n+num<<endl;
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;
//T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
1972D1-数学
/*
* @Author : Danc1ng
* @Date : 2024-05-10 20:54:08
* @FilePath : 1972D1
* @Origin : https://codeforces.com/contest/1972/problem/D1
* @Description:
* 给两个正整数n,m,求满足a+b是b*gcd(a,b)的倍数的(a,b)的个数 (1<=a<=n,1<=b<=m);
* @Solution :
*
* gcd(a,b)*b|a+b => k*b*gcd(a,b)=a+b => k*gcd(a,b)=a/b+1 因为gcd(a,b)和k都是整数,
* 所以a/b+1 为整数 => a/b为整数 => b|a => b * b | a + b
* kb+b是b^2的倍数,即k+1是b的倍数,因为a+b<=n+b,所以k+1<=n+b/b,
* 那么当前的贡献就是k+1/b==n+b/(b^2),枚举b即可
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 2e5 + 10 , INF = 2e9;
int n,m;
void solve()
{
cin>>n>>m;
int ans=0;
for(int i=1;i<=m;i++)
{
ans+=(n+i)/(i*i);
if(i==1) ans--;//b=1 时贡献为n
}
cout<<ans<<endl;
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;
//T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
1972D2- 数学
/*
* @Author : Danc1ng
* @Date : 2024-05-10 20:54:18
* @FilePath : 1972D2
* @Origin :
* @Description:
* 给两个正整数n,m,求满足b*gcd(a,b)是a+b的倍数的(a,b)的个数 (1<=a<=n,1<=b<=m);
* @Solution :
* 当gcd(a,b) == 1时,a+b|b 不成立
* 当gcd(a,b) != 1时,设gcd(a,b)==g, a=g*ka,b=g*kb, b*g是g(ka+kb)的倍数,b是ka+kb的倍数
* g*kb 是ka+kb的倍数,所以g是ka+kb的倍数,枚举gcd(ka,kb) == 1的所有(ka,kb) 在看g为ka+kb的倍数情况
* 但是O(n*m)的复杂度, 所以要缩小ka和kb的枚举范围, g是ka+kb的倍数,所以g>ka,ka*ka<g*ka=a<=n,
* 所以ka<=sqrt(n),同理kb<=sqrt(m);
*
* 因为a=g*ka<=n,b=g*kb<=m,所以g最大可以是min(n/ka,m/kb)
*/
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
using namespace std;
typedef pair<int, int> PII;
constexpr int N = 2e5 + 10 , INF = 2e9;
int n,m;
void solve()
{
cin>>n>>m;
int ans=0;
for(int i=1;i<=sqrt(n);i++)
{
for(int j=1;j<=sqrt(m);j++)
{
if(__gcd(i,j)==1)
{
int k=min(n/i,m/j);
ans+=k/(i+j);
}
}
}
cout<<ans<<endl;
}
signed main()
{
//freopen("check.in","r",stdin);
//freopen("check.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;
//T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!