前言
怎么这场难度跨度这么大。
怎么 kdfz 还藏人的。
结果是 100+100+0+0。一坨人这个分然后并列 rk1。
Rating 变化:\(2121\to 2148\)。大胜利。
推歌:KOTONOHOUSE / rinahamu - I WANNA UNDERSTAND YOU
I wanna understand you - I wanna understand you
But, I’ll never understand you
理解り合いたいけど きっと出来ないんだ 僕らには / 虽然想要相互理解 但我们注定无法做到
I wanna understand you - I wanna understand you
Bad, I’ll never understand you
違う宇宙、世界線で笑っていたいよ / 想要在各自不同的宇宙和世界线里绽放笑容
T1 五彩斑斓(colorful)
题意
给定一个 \(n\times m\) 的矩阵,位置 \((i,j)\) 有颜色 \(c_{i,j}\)。
问这个矩阵有多少个子矩阵满足其四个角的颜色不都相同。
\(1\le n,m\le 400\),\(0\le c_{i,j}\le 10^6\)。
题解
hxf 容斥模板题。
考虑到 \(O(n^2m)\) 可过。
所以枚举两行,再扫一遍列,当这一列的两个数相等的时候才可能贡献答案。
所以开个桶记录一下当前出现次数就行。记得清空。
需要注意自己和自己也可能被计算。
诶我赛时写的怎么和题解一模一样。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3f
using namespace std;int n,m;
int a[410][410];
long long cnt[1000010];long long b[410][410];int main(){ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];long long sum=0;for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) sum+=(1ll*i*j);for(int i=1;i<=n;i++){for(int j=1;j<=i;j++){for(int k=1;k<=m;k++) if(a[i][k]==a[j][k]) cnt[a[i][k]]++,sum-=cnt[a[i][k]];for(int k=1;k<=m;k++) if(a[i][k]==a[j][k]) cnt[a[i][k]]=0;}}cout<<sum<<"\n";# ifndef ONLINE_JUDGEcerr<<"\nUsed time: "<<clock()*1.0/CLOCKS_PER_SEC<<"s.\n";# endifreturn 0;
}
T2 错峰旅行(travel)
题意
给定一张 \(n\) 个点的无向完全图,起始时刻 \(S\),终止时刻 \(T\) 和 \(m\) 个形如 \((x,l,r)\) 的限制。
对于每个限制 \((x,l,r)\),表示时刻 \([l,r]\) 内点 \(x\) 不合法。
一个合法方案是一个序列 \(c_S,c_{S+1},\dots,c_T\),其中 \(\forall i\in [S,T]\),点 \(c_i\) 在时刻 \(i\) 合法。
求合法方案总数。
答案对 \(10^9+7\) 取模。
\(1\le n\le 5000\),\(1\le m\le 10^6\),\(0\le S\le l\le r\le T\le 10^9\)。
题解
不难发现答案的递推式:\(f_i=f_{i-1}\times c_i\)。其中 \(c_i\) 代表 \(i\) 时刻合法的点总数。
然后发现有一坨时间的 \(c_i\) 都相等。
所以套个扫描线带上快速幂就做完了。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3f
using namespace std;const long long mod=1e9+7;
long long qpow(long long x,long long a){long long res=1;while(a){if(a&1) res=res*x%mod;x=x*x%mod;a>>=1;}return res;
}int n,m,S,T;
struct node{int time,v;bool operator<(const node&_Q)const{return time<_Q.time;}
};vector<node> vec,e;int main(){ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>n>>m>>S>>T;for(int i=1;i<=m;i++){int x,l,r;cin>>x>>l>>r;vec.push_back({l,-1});vec.push_back({r+1,1});}vec.push_back({S,0});vec.push_back({T+1,0});sort(vec.begin(),vec.end());e.push_back(vec[0]);for(int i=1;i<(int)vec.size();i++){if(vec[i-1].time==vec[i].time) e.back().v+=vec[i].v;else e.push_back(vec[i]);}int nows=n+e[0].v;long long ans=1;for(int i=1;i<(int)e.size();i++){(ans*=qpow(nows,e[i].time-e[i-1].time))%=mod;nows+=e[i].v;}cout<<ans<<"\n";# ifndef ONLINE_JUDGEcerr<<"\nUsed time: "<<clock()*1.0/CLOCKS_PER_SEC<<"s.\n";# endifreturn 0;
}
T3 线段树(segment)
题意
你要构建一棵长度为 \(n\) 的线段树。定义 \(f_{l,r}\) 表示询问 \([l,r]\) 区间时需要访问的最少区间个数。
给定 \(q\) 组询问,形如 \((l,r)\)。
你可以任取线段树构建时分隔区间的 \(mid\)。
最小化 \(\sum _{i=1}^{q} f_{l_i,r_i}\),求出这个值。
\(1\le l\le r\le n\le 500\),\(1\le q\le 10^5\)。
题解
显然的区间 dp。
但我赛时状态设错导致挂完了。
考虑一个区间 \([l',r']\),在 \(k\sim k+1\) 处切开,会使一个询问 \([l,r]\) 答案增加的条件:
- \([l',r']\cap [l,r]\ne \emptyset\) 且 \([l',r']\nsubseteq [l,r]\)。
- \(k,k+1\in [l,r]\)。
我们记同时包含 \(k,k+1\) 两个位置的询问区间数量为 \(w_k\),包含 \([i,j]\) 的询问区间的数量为 \(num_{i,j}\)。
前者是个差分,后者可以用一个二维前缀和状物维护。
然后一次转移就长这样:
然后就做完了。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3f
using namespace std;int n,m;
int w[510];
int num[510][510];long long dp[510][510];int main(){ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>n>>m;for(int i=1;i<=m;i++){int l,r;cin>>l>>r;w[l]++,w[r]--;num[l][r]++;}for(int i=1;i<=n;i++) w[i]+=w[i-1];for(int len=n-1;len>=1;len--){for(int l=1;l+len-1<=n;l++){int r=l+len-1;num[l][r]+=num[l-1][r]+num[l][r+1]-num[l-1][r+1];}}for(int len=2;len<=n;len++){for(int l=1;l+len-1<=n;l++){int r=l+len-1;dp[l][r]=infll;for(int i=l;i<r;i++) dp[l][r]=min(dp[l][r],dp[l][i]+dp[i+1][r]+(w[i]-num[l][r]));}}cout<<dp[1][n]+m<<"\n";# ifndef ONLINE_JUDGEcerr<<"\nUsed time: "<<clock()*1.0/CLOCKS_PER_SEC<<"s.\n";# endifreturn 0;
}
总结
怎么总感觉我能看懂 T4 题解但我又看不懂。。