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

\(1\sim n\) 顺序执行即可。

#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(n^3)\)

#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)\) 代表 \(1\sim x\) 中有多少合法的数。

\(f(x)=\lfloor \frac{x}{n}\rfloor+\lfloor\frac{x}{m}\rfloor-2\times\lfloor\frac{x}{\operatorname{lcm}(n,m)}\rfloor\)

二分出最小的满足 \(f(x)\ge k\)\(x\) 即可,时间复杂度 \(O(\log n)\)

#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

显然,反转序列对于序列内部的关系是不会改变的,会改变的只有 \(l-1,l\)\(r,r+1\) 之间的关系。

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

注意,查询时要检查 \(l\sim r-1\) 中的标记数目,而不是 \(l-1\sim r\)

什么?为什么不用 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

纪念一下赛时看错 \(w_i\) 的范围导致痛失F

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

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

\[dp_x=\sum_{y\in S}dp_y+1 \]

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

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

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

  • \(\sum\limits_{y\in S}W_y<W_x\)

同时需要最大化 \(\sum\limits_{y\in S}dp_y\)

我们将 \(W_y\) 视为体积,\(dp_y\) 视为价值,这就可以利用背包求解。

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

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

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

#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 @ 2024-02-18 11:49  BYR_KKK  阅读(19)  评论(0)    收藏  举报