ABC340
A
模拟即可。
#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
从 \(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
暴力判断即可,复杂度 \(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
定义 \(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
显然,反转序列对于序列内部的关系是不会改变的,会改变的只有 \(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
纪念一下赛时看错 \(w_i\) 的范围导致痛失F
考虑对于最小的 \(W_i\),对应的集合 \(S\) 一定为空,所以如果 \(i\) 上放一个棋子,对总操作数产生的贡献为 \(1\),我们把在 \(i\) 上放一个棋子,对总操作数产生的贡献记为 \(dp_i\)。
这就启发我们按照 \(W_i\) 进行排序,对于 \(x\) 来说,所有可选择的 \(y\) 一定在 \(x\) 的前面,因为 \(W_y<W_x\)。即所有的 \(dp_y\) 已经处理好,我们需要选出一个集合 \(S\) 进行转移。
因为当在 \(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

浙公网安备 33010602011771号