Codeforces 1710 A,B,C,E
A,C做时没有遇到太多困难,所以这里就略写。
既然E是一个Well-Known Problem,那么也写一下E的题解吧。
A
容易发现最终一定是若干行组成的一个条状的东西,这样之间暴力即可。
B
首先观察到积水量最大的点一定是某次降雨的中心。
第一个问题就是我们如何求出所有降雨中心的积水量。
区间加同一个数,我们可以想到差分。
那么区间加呢?使用二维差分。
具体的,对于一次降雨,那么二维差分数组。
对二维差分进行一次前缀和,就可以得到一维差分;再进行一次前缀和,就可以得到各个点的降雨量。
对于坐标负数,这个很好解决——使用map存储差分数组;但是我们发现,二维差分点数是的,但是对二维差分做两次前缀和后,这个数组的长度会很大,所以要想得到原先点的降雨量,不能暴力做。我们可以之间用二维差分数组直接得到各个点的降雨量,具体的,如果我们要计算点的降雨量,那么我们找到所有的差分数组,其贡献是。所以我们就可以直接写出下面的程序:
scanf("%d%lld",&n,&m);
std::map<ll,ll> ch;
std::vector<ll> pos,val;
for(int i=1;i<=n;i++) {
scanf("%lld%lld",&x[i],&p[i]);
ch[x[i]-p[i]]++;
ch[x[i]]-=2;
ch[x[i]+p[i]]++;
pos.push_back(x[i]);
id[i]=i;
}
std::sort(pos.begin(),pos.end());
pos.erase(std::unique(pos.begin(),pos.end()),pos.end());
std::map<ll,ll>::iterator it=ch.begin();
ll sum=0,now=0;
for(int i=0;i<(int)pos.size();i++) {
if(i) sum+=(pos[i]-pos[i-1])*now;
while(it!=ch.end()&&it->first<pos[i]) {
now+=it->second;
sum+=(pos[i]-it->first)*(it->second);
it++;
}
val.push_back(sum);
}
于是我们得到每个降雨中心的位置和对应的积水量。如果我们撤销第次降水,那么必须满足对于所有的:
- ,则必须小于等于。
- ,则必须小于等于。
化简这两个式子:
这可以用两个set存储。
具体程序见:
#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl
using ll=long long;
const int maxn=200005;
int n;
ll m,x[maxn],p[maxn],id[maxn],ans[maxn];
bool cmp(int id1,int id2) {
return x[id1]<x[id2];
}
void solve() {
scanf("%d%lld",&n,&m);
std::map<ll,ll> ch;
std::vector<ll> pos,val;
for(int i=1;i<=n;i++) {
scanf("%lld%lld",&x[i],&p[i]);
ch[x[i]-p[i]]++;
ch[x[i]]-=2;
ch[x[i]+p[i]]++;
pos.push_back(x[i]);
id[i]=i;
}
std::sort(pos.begin(),pos.end());
pos.erase(std::unique(pos.begin(),pos.end()),pos.end());
std::map<ll,ll>::iterator it=ch.begin();
ll sum=0,now=0;
for(int i=0;i<(int)pos.size();i++) {
if(i) sum+=(pos[i]-pos[i-1])*now;
while(it!=ch.end()&&it->first<pos[i]) {
now+=it->second;
sum+=(pos[i]-it->first)*(it->second);
it++;
}
val.push_back(sum);
}
std::sort(id+1,id+n+1,cmp);
std::multiset<ll> S,T;
for(int i=0;i<(int)pos.size();i++) {
if(val[i]>m) S.insert(val[i]-m+pos[i]);
}
for(int i=1,j=0;i<=n;i++) {
while(j<(int)pos.size()&&pos[j]<=x[id[i]]) {
if(val[j]>m) {
S.erase(S.find(val[j]-m+pos[j]));
T.insert(val[j]-m-pos[j]);
}
j++;
}
bool r1=S.empty()||*S.rbegin()<=p[id[i]]+x[id[i]];
bool r2=T.empty()||*T.rbegin()<=p[id[i]]-x[id[i]];
if(r1&&r2) {
ans[id[i]]=1;
} else {
ans[id[i]]=0;
}
}
for(int i=1;i<=n;i++) putchar(ans[i]+'0');
putchar('\n');
}
int main() {
int T; scanf("%d",&T);
while(T--) solve();
return 0;
}
C
一道比较板子的数位DP。设表示考虑了的前位,在只考虑前位的情况下,与的大小关系为,与、与、与的大小关系为,此时合法的方案数。
转移也是比较简单的。
#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl
using ll=long long;
const ll mod=998244353;
int n;
std::string str;
ll f[200005][2][2][2][2][2][2];
#define REP(i,x,y) for(int (i)=(x);(i)<(y);(i)++)
int main() {
std::cin>>str;
std::reverse(str.begin(),str.end());
n=str.size();
str=" "+str;
REP(a,0,2) REP(b,0,2) REP(c,0,2) {
int dig=str[1]-'0';
int s1=a>dig,s2=b>dig,s3=c>dig;
int x=a^b,y=b^c,z=a^c;
int t1=x+y>z,t2=x+z>y,t3=y+z>x;
f[1][s1][s2][s3][t1][t2][t3]++;
}
REP(i,1,n) REP(s1,0,2) REP(s2,0,2) REP(s3,0,2) REP(t1,0,2) REP(t2,0,2) REP(t3,0,2) {
REP(a,0,2) REP(b,0,2) REP(c,0,2) {
int i_=i+1;
int dig=str[i+1]-'0';
int s1_=(dig==a?s1:(dig<a?1:0));
int s2_=(dig==b?s2:(dig<b?1:0));
int s3_=(dig==c?s3:(dig<c?1:0));
int x=a^b,y=b^c,z=a^c;
int t1_=(z==x+y?t1:(z<x+y?1:0));
int t2_=(y==x+z?t2:(y<x+z?1:0));
int t3_=(x==y+z?t3:(x<y+z?1:0));
f[i+1][s1_][s2_][s3_][t1_][t2_][t3_]+=f[i][s1][s2][s3][t1][t2][t3];
f[i+1][s1_][s2_][s3_][t1_][t2_][t3_]%=mod;
}
}
printf("%lld\n",f[n][0][0][0][1][1][1]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话