ABC340

A

link

模拟即可。

#include<bits/stdc++.h>
#define int long long
template<typename T>
void read(T &x){
int f=1;
char c=getchar();
x=0;
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
template<typename T,typename I>
void chkmin(T &a,I b){
a=std::min(a,b);
}
template<typename T,typename I>
void chkmax(T &a,T b){
a=std::max(a,b);
}
const int inf=1e18+10,MOD1=998244353,MOD2=1e9+7;
signed main(){
int n;
read(n);
int now=1;
for(int i=1;i<=n+n+1;i++) {
if(i&1) putchar('1');
else putchar('0');
}
return 0;
}
/*
-读入字符一定检查回车
- 能不能搜索?
-函数要有返回值!
-想好了再写!
*/

B

link

1n 顺序执行即可。

#include<bits/stdc++.h>
#define int long long
template<typename T>
void read(T &x){
int f=1;
char c=getchar();
x=0;
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
template<typename T,typename I>
void chkmin(T &a,I b){
a=std::min(a,b);
}
template<typename T,typename I>
void chkmax(T &a,T b){
a=std::max(a,b);
}
const int inf=1e18+10,MOD1=998244353,MOD2=1e9+7;
const int maxn=2e5+10;
int a[maxn];
signed main(){
int n;
read(n);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<n;i++){
int s,t;
read(s),read(t);
int sum=a[i]/s;
a[i+1]+=t*sum;
}
printf("%lld",a[n]);
return 0;
}
/*
-读入字符一定检查回车
- 能不能搜索?
-函数要有返回值!
-想好了再写!
*/

C

link

暴力判断即可,复杂度 O(n3)

#include<bits/stdc++.h>
#define int long long
template<typename T>
void read(T &x){
int f=1;
char c=getchar();
x=0;
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
template<typename T,typename I>
void chkmin(T &a,I b){
a=std::min(a,b);
}
template<typename T,typename I>
void chkmax(T &a,T b){
a=std::max(a,b);
}
const int inf=1e18+10,MOD1=998244353,MOD2=1e9+7;
const int maxn=510;
int a[maxn][maxn];
char c[maxn];
signed main(){
int h,w,n;
std::cin>>h>>w>>n;
for(int i=1;i<=n;i++){
std::cin>>c[i];
}
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++){
char cc;
std::cin>>cc;
if(cc=='.') a[i][j]=1;
}
int sum=0;
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++){
bool flag=1;
int l=i,r=j;
if(a[l][r]==0) flag=0;
for(int k=1;k<=n;k++){
if(!flag) break;
if(c[k]=='L') r--;
if(c[k]=='R') r++;
if(c[k]=='U') l--;
if(c[k]=='D') l++;
if(a[l][r]==0){
flag=0;
break;
}
}
if(flag) sum++;
}
printf("%lld",sum);
return 0;
}
/*
-读入字符一定检查回车
- 能不能搜索?
-函数要有返回值!
-想好了再写!
*/

D

link

定义 f(x) 代表 1x 中有多少合法的数。

f(x)=xn+xm2×xlcm(n,m)

二分出最小的满足 f(x)kx 即可,时间复杂度 O(logn)

#include<bits/stdc++.h>
#define int long long
template<typename T>
void read(T &x){
int f=1;
char c=getchar();
x=0;
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
template<typename T,typename I>
void chkmin(T &a,I b){
a=std::min(a,b);
}
template<typename T,typename I>
void chkmax(T &a,T b){
a=std::max(a,b);
}
const int inf=1e18+10,MOD1=998244353,MOD2=1e9+7;
signed main(){
int n,m,k;
read(n),read(m),read(k);
if(n>m) std::swap(n,m);
int l=1,r=1e20;
while(l<=r){
int mid=(l+r)>>1;
int sum=mid/n+mid/m-mid/(n*m/std::__gcd(n,m))*2;
if(sum<k) l=mid+1;
else r=mid-1;
}
printf("%lld\n",r+1);
return 0;
}
/*
-读入字符一定检查回车
- 能不能搜索?
-函数要有返回值!
-想好了再写!
*/

E

link

显然,反转序列对于序列内部的关系是不会改变的,会改变的只有 l1,lr,r+1 之间的关系。

对于相邻两个不同的数,在前面一个数打上标记,线段树维护区间标记数目即可。

注意,查询时要检查 lr1 中的标记数目,而不是 l1r

什么?为什么不用 BIT?当然是因为我太弱了。

#include<bits/stdc++.h>
#define int long long
template<typename T>
void read(T &x){
int f=1;
char c=getchar();
x=0;
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
template<typename T,typename I>
void chkmin(T &a,I b){
a=std::min(a,b);
}
template<typename T,typename I>
void chkmax(T &a,T b){
a=std::max(a,b);
}
const int inf=1e18+10,MOD1=998244353,MOD2=1e9+7;
const int maxn=5e5+10;
int a[maxn];
int t[maxn];
struct node{
int l,r,sum,ls,rs;
}s[maxn<<1];
void push_up(int p){
s[p].sum=s[s[p].ls].sum+s[s[p].rs].sum;
}
int tot=0;
int build(int l,int r){
int p=++tot;
s[p].l=l,s[p].r=r;
if(l==r){
s[p].sum=t[l];
// printf("##%lld %lld %lld\n",l,l,s[p].sum);
return p;
}
int mid=(l+r)>>1;
s[p].ls=build(l,mid);
s[p].rs=build(mid+1,r);
push_up(p);
// printf("##%lld %lld %lld\n",l,r,s[p].sum);
return p;
}
void update(int p,int L,int R,int k){
int l=s[p].l,r=s[p].r;
if(l>=L&&r<=R){
s[p].sum+=k;
return ;
}
int mid=(l+r)>>1;
if(mid>=L) update(s[p].ls,L,R,k);
if(R>mid) update(s[p].rs,L,R,k);
push_up(p);
return ;
}
int query(int p,int L,int R){
int l=s[p].l,r=s[p].r;
if(l>=L&&r<=R) return s[p].sum;
int mid=(l+r)>>1;
int ret=0;
if(mid>=L) ret+=query(s[p].ls,L,R);
if(R>mid) ret+=query(s[p].rs,L,R);
return ret;
}
signed main(){
int n,q;
std::cin>>n>>q;
for(int i=1;i<=n;i++) {
char c;
std::cin>>c;
a[i]=(int)(c-'0');
if(i!=1&&a[i]==a[i-1]) t[i-1]=1;//,printf("&&%lld\n",i-1);
}
build(1,n);
// printf("%lld\n",query(1,0,5));
while(q--){
int opt,l,r;
std::cin>>opt>>l>>r;
if(opt==1){
if(l!=1){
if(query(1,l-1,l-1)==1) update(1,l-1,l-1,-1);
else update(1,l-1,l-1,1);
}
if(r!=n){
if(query(1,r,r)==1) update(1,r,r,-1);
else update(1,r,r,1);
}
}else {
if(l==1){
if(query(1,l,r-1)==0) printf("Yes\n");
else printf("No\n");
continue;
}
if(query(1,l,r-1)==0) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
/*
-读入字符一定检查回车
- 能不能搜索?
-函数要有返回值!
-想好了再写!
*/

F

link

纪念一下赛时看错 wi 的范围导致痛失F

考虑对于最小的 Wi,对应的集合 S 一定为空,所以如果 i 上放一个棋子,对总操作数产生的贡献为 1,我们把在 i 上放一个棋子,对总操作数产生的贡献记为 dpi

这就启发我们按照 Wi 进行排序,对于 x 来说,所有可选择的 y 一定在 x 的前面,因为 Wy<Wx。即所有的 dpy 已经处理好,我们需要选出一个集合 S 进行转移。

dpx=ySdpy+1

因为当在 x 上移除一个棋子后,S 中所有的 y 都会得到一个棋子,然后再加上在 x 上的一次操作即可。

现在问题变成了,如何求出 S

集合 S 应该满足如下限制:

  • ySWy<Wx

同时需要最大化 ySdpy

我们将 Wy 视为体积,dpy 视为价值,这就可以利用背包求解。

时间复杂度 O(MWmax),瓶颈在于多遍背包。

细节:我们对 Wi 排序后,边遍历序列边连边能使得代码更简洁。

注意处理好排序前后下标不同的细节。

#include<bits/stdc++.h>
#define int long long
#define pr printf
#define ok pr("----------------\n")
template<typename T>
void read(T &x){
int f=1;
char c=getchar();
x=0;
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
template<typename T,typename I>
void chkmin(T &a,I b){
a=std::min(a,b);
}
template<typename T,typename I>
void chkmax(T &a,I b){
a=std::max(a,b);
}
const int inf=1e18+10,MOD1=998244353,MOD2=1e9+7;
const int maxn=5010;
struct node{
int a,w,v,opt,bt,ct;//v 代表如果在该点上放一个棋子能产生多大的贡献 bt 代表 b 中有多少点 ct 代表 c 中有多少点
int b[5010],c[5010];//b 代表初始连边情况 c 代表边遍历边连边的情况
}s[maxn];
bool cmp1(node s1,node s2){
return s1.w<s2.w;
}
int t[maxn],dp[maxn][maxn];
signed main(){
int n,m;
read(n),read(m);
for(int i=1;i<=m;i++){
int u,v;
read(u),read(v);
s[u].b[++s[u].bt]=v;
s[v].b[++s[v].bt]=u;
}
for(int i=1;i<=n;i++) read(s[i].w),s[i].opt=i;
for(int i=1;i<=n;i++) read(s[i].a);
std::sort(s+1,s+n+1,cmp1);//按照 w 对点进行排序
for(int i=1;i<=n;i++) t[s[i].opt]=i;//记录排序后在哪
int ans=0;
for(int i=1;i<=n;i++){
s[i].v=1;
for(int ii=1;ii<=s[i].ct;ii++)
for(int j=0;j<=s[i].w;j++) dp[ii][j]=-inf;//init
dp[0][0]=0;
int cnt=0;
for(int _=1;_<=s[i].ct;_++){//背包
int p=s[i].c[_];
cnt++;
for(int j=0;j<s[i].w;j++){
dp[cnt][j]=dp[cnt-1][j];
if(j>=s[p].w) chkmax(dp[cnt][j],dp[cnt-1][j-s[p].w]+s[p].v);
}
}
int nowans=-inf;
for(int j=0;j<s[i].w;j++) chkmax(nowans,dp[cnt][j]);
s[i].v+=nowans;
ans+=s[i].v*s[i].a;
for(int _=1;_<=s[i].bt;_++){
int p=s[i].b[_];
if(s[t[p]].w>s[i].w) s[t[p]].c[++s[t[p]].ct]=i;//连边
}
}
printf("%lld",ans);
return 0;
}
/*
-读入字符一定检查回车
- 能不能搜索?
-函数要有返回值!
-想好了再写!
*/

G

ABC340 G

posted @   BYR_KKK  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示