我们刚刚知道那些题的解法-5
Zhengrui 2022ABDay1 B
考虑进行转化,在一个格子内,如果某条边有水管连接,那么就是
一个状态合法等价于所有边两边标的数都是一样的,最外围的边都认为值标
若一个格子里填的是高级水管,那么就是好格子,否则就是坏格子。
考虑一行所有竖着的边,如果两个边标的数相同,且之间的边数为奇数,那么里面一定有一个坏格子。如果标的数不同,一样有类似的限制。
不难发现我们仅有这样的限制,也就是说,如果所有限制都满足,那么一定可以构造出合法解。
考虑把所有行限制放在左边,所有列限制放在右边,考虑如果两个限制有交点,那么连一条边。限制的个数确实是
没有边相连的点一定有一个
不过还有两个限制没有考虑:某个格子必须是好格子以及某个格子我不能填好格子。
首先如果某个格子我不能填好格子的话,那么它一定是没有任何贡献的,我们按照需要填就可以。
至于某个格子必须是好格子这个限制,其实也是好做的,我们只需要关注所有限制是否满足,即是否存在一个限制里面所有的格子都要求是好的。
struct edge{
int to,next,f;
inline void Init(int to_,int ne_,int f_){
to=to_;next=ne_;f=f_;
}
}li[N*N<<1];
int head[N*N*N],now[N*N*N],tail=1,n,m,de[N*N*N],tot,c[N],pl[N][N],pr[N][N];
bool flag=1;
int s,t,d[N*N*N];
char a[N][N];
vi L,R;
inline void Add(int from,int to,int f){
li[++tail].Init(to,head[from],f);head[from]=tail;
swap(from,to);li[++tail].Init(to,head[from],0);head[from]=tail;
}
queue<int> q;
inline bool bfs(){
mset(d,0);
q.push(s);d[s]=1;
while(q.size()){
int top=q.front();q.pop();now[top]=head[top];
Next(top){
int to=li[x].to,f=li[x].f;
if(d[to]||!f) continue;
d[to]=d[top]+1;q.push(to);
}
}
if(d[t]) return 1;return 0;
}
inline int Dinic(int k,int flow){
if(k==t) return flow;
int rest=flow,x;
for(x=now[k];x&&rest;x=li[x].next){
int to=li[x].to,f=li[x].f;
if(d[to]!=d[k]+1||!f) continue;
int re=Dinic(to,min(rest,f));
if(!re) d[to]=-INF;
rest-=re;li[x].f-=re;li[x^1].f+=re;
}
now[k]=x;
return flow-rest;
}
inline int RunDinic(){
int ans=0;
while(bfs()){
ans+=Dinic(s,INF);
}
return ans;
}
inline void chk(int x,int k){
if(c[x]==-1) c[x]=k;else if(c[x]!=k) flag=0;
}
int main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);read(m);
rep(i,1,n){
scanf("%s",a[i]+1);
}
rep(i,1,n){
mset(c,-1);
c[1]=0;c[m+1]=0;
rep(j,1,m){
if(a[i][j]=='1'||a[i][j]=='2') chk(j,1),chk(j+1,0);
else if(a[i][j]=='3'||a[i][j]=='4') chk(j,0),chk(j+1,1);
}
for(int j=1,k=2;j<=m+1&&k<=m+1;j=k++){
while(c[k]==-1) k++;
if(((k-j)&1)==(c[k]^c[j])) continue;
bool ok=0;
rep(o,j,k-1) if(a[i][o]=='x') ok=1;
if(ok) continue;
rep(o,j,k-1) if(a[i][o]=='.') ok=1;
if(!ok){
flag=0;continue;
}
tot++;L.pb(tot);
rep(o,j,k-1) pl[i][o]=tot;
}
}
rep(j,1,m){
mset(c,-1);
rep(i,1,n){
if(a[i][j]=='1'||a[i][j]=='3') chk(i,1),chk(i+1,0);
if(a[i][j]=='2'||a[i][j]=='4') chk(i,0),chk(i+1,1);
}
c[1]=0;c[n+1]=0;
for(int i=1,k=2;i<=n+1&&k<=n+1;i=k++){
while(c[k]==-1) k++;
if(((k-i)&1)==(c[k]^c[i])) continue;
bool ok=0;
rep(o,i,k-1) if(a[o][j]=='x') ok=1;
if(ok) continue;
rep(o,i,k-1) if(a[o][j]=='.') ok=1;
if(!ok){
flag=0;continue;
}
tot++;R.pb(tot);
rep(o,i,k-1) pr[o][j]=tot;
}
}
if(!flag){
puts("-1");return 0;
}
rep(i,1,n)rep(j,1,m){
if(a[i][j]=='.'&&pl[i][j]&&pr[i][j]){
Add(pl[i][j],pr[i][j],1);
de[pl[i][j]]++;
de[pr[i][j]]++;
}
}
s=++tot;t=++tot;
for(int x:L){
if(de[x]) Add(s,x,1);
}
for(int x:R){
if(de[x]) Add(x,t,1);
}
int ans=n*m;
rep(i,1,n)rep(j,1,m){
if(a[i][j]=='x') ans--;
}
int cnt=0;
for(int x:L) if(!de[x]) ans--;else cnt++;
for(int x:R) if(!de[x]) ans--;else cnt++;
ans-=(cnt-RunDinic());
printf("%d\n",ans);
return 0;
}
Zhengrui 2022ABDay1 C
考虑设
考虑转移,显然如果
不难证明最优解的方案一定是包含在其中的。而其余的方案一定都是合法的,这保证了做法的正确性,代码复杂度完虐 std 做法。
#include <bits/stdc++.h>
using namespace std;
long long n,a[1010],t,d,s,dis[1010][1010],f[1010][1010],g[1010];
vector<pair<int,int> >v[1010];
void DFS(int rt,int x,int fa){
for(int i=0;i<v[x].size();i++){
int to=v[x][i].first;
long long val=v[x][i].second;
if(to==fa)continue;
dis[rt][to]=dis[rt][x]+val;
DFS(rt,to,x);
}
}
void dfs(int x,int fa){
for(int i=0;i<v[x].size();i++){
int to=v[x][i].first;
if(to==fa)continue;
dfs(to,x);
}
for(int i=1;i<=n;i++){
f[x][i]=a[x]*(dis[x][i]<=d)-s;
for(int j=0;j<v[x].size();j++){
int to=v[x][j].first;
if(to==fa)continue;
f[x][i]+=max(g[to],f[to][i]+s);
}
}
for(int i=1;i<=n;i++)g[x]=max(g[x],f[x][i]);
}
int main(){
scanf("%lld%lld%lld%lld",&n,&t,&d,&s);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]*=t;
for(int i=1;i<n;i++){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
v[x].push_back({y,w});
v[y].push_back({x,w});
}
for(int i=1;i<=n;++i)DFS(i,i,0);
dfs(1,0);
printf("%lld\n",g[1]);
}
这里由于不想写了,粘了别人的一份代码过来。
考虑 std 做法怎么做。转移其实只需要知道
转移是一个树形 DP,不过要我的做法要大分讨。
看了下 maoyiting 的代码,发现其实都可以用背包来转移,全都放在背包里进行转移显然能有效降低代码复杂度。
Zhengrui 2022NOIPDay4 B
感觉思路还是比较自然的。首先考虑是一个排列怎么做,考虑里面
考虑设
int n,a[N],f[N][N][N],cnt[N],po[N];
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);rep(i,1,n) read(a[i]);
rep(i,1,n) cnt[a[i]]++;
rep(i,1,n) cnt[i]+=cnt[i-1];
dec(i,1,n) a[i]=cnt[a[i]]--;
// rep(i,1,n) printf("%lld ",a[i]);puts("");
rep(i,1,n) po[a[i]]=i;
rep(i,1,n){
rep(j,0,n) f[i][i][j]=1;
}
rep(i,2,n){
rep(j,1,n-i+1){
int l=j,r=j+i-1;
f[l][r][0]=1;
int minn=INF,maxx=-INF;
rep(k,l,r) cmin(minn,a[i]),cmax(maxx,a[i]);
rep(x,1,n){
int posi=po[x];
if(posi<l||posi>r){
f[l][r][x]=f[l][r][x-1];
// printf("f[%d][%d][%d]=%d\n",l,r,x,f[l][r][x]);
continue;
}
if(posi==r){
f[l][r][x]=f[l][r][x-1];
// printf("f[%d][%d][%d]=%d\n",l,r,x,f[l][r][x]);
continue;
}
rep(k,posi,r-1){
if(a[k]>x) continue;
f[l][r][x]=(f[l][r][x]+f[l][k][x-1]*f[k+1][r][x]%mod)%mod;
}
if(a[r]<=x) (f[l][r][x]+=f[l][r][x-1])%=mod;
// printf("f[%d][%d][%d]=%d\n",l,r,x,f[l][r][x]);
}
}
}
int ans=f[1][n][n];
printf("%lld\n",ans);
return 0;
}
CF1004D
由于对称,不妨设
CF677D
设
考虑把这两个结合一下:设
证明复杂度是正确的,考虑
考虑
所以复杂度是正确的。
CF contest1737 D
显然把每条边移到
ZR 2354
考虑枚举一下种族显然是可以做到
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define N 3010
#define M number
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
const int mod=998244353;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int n,c[N],f[N][2*N],cnt[N],v[N],siz[N],m,base,g[2*N],ans;
vi e[N];
inline void dfs(int k,int fat){
siz[k]=1;
rep(i,-m,m) f[k][i+base]=0;
if(v[k]==1) f[k][base+1]=1;
else f[k][base-1]=1;
for(int to:e[k]) if(to!=fat) dfs(to,k);
for(int to:e[k]) if(to!=fat){
rep(i,-m,m) g[i+base]=0;
rep(i,max(-siz[k],-m),min(siz[k],m)){
rep(j,max(-m-i,max(-siz[to],-m)),min(m-i,min(siz[to],m))){
g[i+j+base]=(g[i+j+base]+f[k][i+base]*f[to][j+base]%mod)%mod;
}
}
siz[k]+=siz[to];
rep(i,-m,m) f[k][i+base]=(f[k][i+base]+g[i+base])%mod;
}
// rep(i,-siz[k],siz[k]){
// printf("f[%d][%d]=%d\n",k,i,f[k][i+base]);
// }
rep(i,1,m) ans=(ans+f[k][i+base])%mod;
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);rep(i,1,n) read(c[i]);
rep(i,1,n-1){
int u,v;read(u);read(v);e[u].pb(v);e[v].pb(u);
}
base=n;
rep(i,1,n) cnt[c[i]]++;
rep(i,1,n){
// printf("i=%d\n",i);
// if(c[i]==i) v[i]=1;
// else v[i]=-1;
rep(j,1,n) if(c[j]==i) v[j]=1;else v[j]=-1;
m=cnt[i];
dfs(1,0);
// printf("m=%d\n",m);
// printf("ans=%d\n",ans);
}
printf("%lld\n",ans);
return 0;
}
ZR 2356
经过观察样例,我们可以考虑通过构造出
重点是如何构造出
同时,不难发现之前的
同样,如下构造可以进行
容易发现 LCS 个数确实变成了两倍,只需要考虑是否满足性质即可。不难发现是满足性质的(
ZR 2357
首先可以线段树优化建图跑 spfa,不过没写。
考虑一个朴素的 DP,设
考虑
首先一个想法是对于每一个
复杂度
ZR 2399
稍微手玩以下就会发现如果一个
不妨假设
经过讨论不难发现不用再计算
下面放一张讨论结果。
ZR 2400
观察可知
枚举
注意第二个
两个等差数列相当于一个前缀和一个后缀,考虑预处理之后枚举断点,预处理的时候需要维护中位数,除了线段树,还可以用常数更小的对顶堆来实现,只需要同时维护一个堆的奇数和,奇数个数,偶数和,偶数个数,另一个堆的和和个数就可以了。
详细看代码。
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define N 100010
#define M number
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=1e18;
const dd eps=1e-9;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int n,a[N],ans,pr[N],su[N],b[N];
int sum,cnt[2],sm[2],cn;
priority_queue<int> q1;
priority_queue<int,vc<int>,greater<int> > q2;
inline void push_1(int x){
cnt[x&1]++;
sm[x&1]+=x;
q1.push(x);
}
inline void push_2(int x){
sum+=x;
cn++;
q2.push(x);
}
inline int pop_1(){
int x=q1.top();
cnt[x&1]--;
sm[x&1]-=x;
q1.pop();
return x;
}
inline int pop_2(){
int x=q2.top();
sum-=x;
cn--;
q2.pop();
return x;
}
inline int get_ans(int x){
int o=x&1;
int nowans=(x*cnt[o]-sm[o])/2+(x*cnt[o^1]-sm[o^1]+cnt[o^1])/2+cnt[o^1]+sum-cn*x;
// printf("x=%d nownas=%lld\n",x,nowans);
return nowans;
}
inline void solve(int *f){
while(q1.size()) q1.pop();
while(q2.size()) q2.pop();
sm[0]=sm[1]=cnt[0]=cnt[1]=sum=0;cn=0;
f[0]=0;
rep(i,1,n){
// printf("i=%d\n",i);
if(q2.size()==0){
push_2(b[i]);
int k=q2.top();
f[i]=min(get_ans(k),get_ans(k-1));
continue;
}
int to=q2.top();
if(to<=b[i]) push_2(b[i]);
else push_1(b[i]);
if(q1.size()<i-(i+2)/3){
assert(q2.size());
push_1(pop_2());
}
if(q1.size()>i-(i+2)/3){
assert(q1.size());
push_2(pop_1());
}
int k=q2.top();
f[i]=min(get_ans(k),get_ans(k-1));
}
}
inline void calc(int d){
// printf("d=%d\n",d);
rep(i,1,n) b[i]=a[i]-(i-1)*d;
// rep(i,1,n){
// printf("b[%d]=%d\n",i,b[i]);
// }
solve(pr);reverse(b+1,b+n+1);solve(su);
rep(i,0,n){
ans=min(ans,pr[i]+su[n-i]);
// printf("pr[%d]=%d su[%d]=%d\n",i,pr[i],n-i,su[n-i]);
}
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
ans=INF;
read(n);rep(i,1,n) read(a[i]);
for(int i=1;clock()<=0.8*CLOCKS_PER_SEC;i++) calc(i),calc(-i);
// calc(3);
printf("%lld\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现