『模拟赛』暑假集训CSP提高模拟17
『模拟赛』暑假集训CSP提高模拟17
日常挂分:T4 \(\color{purple}{RE}\) -40pts
不愧是我先天\(\color{purple}{RE}\)圣体
题目真的和题面有关系吗?哦,只和题目背景有关。
T1 符号化方法初探
- 原题:ARC086B
赛时乱搞前缀和,思路没有那么清晰。骗的分还挺多...
正解如果全正(负)就直接 \(n-1\) 次前(后)缀合碾过去,否则记一下绝对值最大的数,经过 \(n-1\) 次操作把她们转成同正(负),之后前(后)缀合跑一遍,最多操作 \(2n-2\) 次。
int n,cnt,a[N];
int mx=0,mn=inf,pos;
struct Move{
int i,j;
}q[N*4];
signed main(){
n=rd;
for(int i=1;i<=n;i++){
a[i]=rd;
if(abs(a[i])>abs(mx)){
mx=a[i];
pos=i;
}
}
for(int i=1;i<=n;i++){
q[++cnt].i=pos,q[cnt].j=i;
}
if(mx>0){
for(int i=2;i<=n;i++){
q[++cnt].i=i-1,q[cnt].j=i;
}
}else if(mx<0){
for(int i=n-1;i;i--){
q[++cnt].i=i+1,q[cnt].j=i;
}
}else{
printf("0");
return Elaina;
}
printf("%lld\n",cnt);
for(int i=1;i<=cnt;i++){
printf("%lld %lld\n",q[i].i,q[i].j);
}
return Elaina;
}
T2 无标号 Sequence 构造
赛时乱糊了一个矩阵乘。
但直接 \(n^3\) 乘的复杂度显然不可接受,考虑随机选点判定。
int n,m;
int a[N][N],b[N][N],c[N][N];
bool vis[N][N];
void cleanall(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j]=b[i][j]=c[i][j]=vis[i][j]=0;
}
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
srand(time(0));
int T;
cin>>T;
while(T--){
cleanall();
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>b[i][j];
}
}
int flg=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>c[i][j];
}
}
int mn=min(1ll*n*n,60000ll);
for(int k=1;k<=mn;k++){
int x=random(1,n),y=random(1,n),cnt=0;
if(vis[x][y]){
k--;
continue;
}
vis[x][y]=1;
for(int i=1;i<=n;i++) cnt+=1ll*a[x][i]*b[i][y],cnt%=mod;
if(cnt!=c[x][y]){
flg=0;
break;
}
}
if(flg){
cout<<"Yes"<<'\n';
}else{
cout<<"No"<<'\n';
}
}
return Elaina;
}
但当 n=3000
时,假设只有一个点是错误的,那么随到这个点的可能性实在太低。
于是你就想到了正解。但我没有
想到矩阵乘法的性质:
一个 \(n\times m\) 的矩阵 $\times $ 一个 \(m\times p\) 的矩阵 \(=\) 一个 \(n\times p\) 的矩阵
同理:
一个 \(n\times n\) 的矩阵 $\times $ 一个 \(n\times 1\) 的矩阵 \(=\) 一个 \(n\times 1\) 的矩阵
将题目改为 \(A\times B\times D = C\times D\),其中 \(D\) 为一个 \(n\times 1\) 的矩阵。
酱紫,就可以在 \(n^2\) 的复杂度下 check 完全部的点了。
矩阵乘不用我教你吧
int n,m;
int a[N][N],b[N][N],c[N][N];
long long d[N],e[N],f[N],g[N];
void cleanall(){
for(int i=1;i<=n;i++){
d[i]=e[i]=f[i]=g[i]=0;
for(int j=1;j<=n;j++){
a[i][j]=b[i][j]=c[i][j]=0;
}
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
srand(time(0));
int T;
cin>>T;
while(T--){
cleanall();
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>b[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>c[i][j];
}
}
bool flg=1;
for(int i=1;i<=n;i++) d[i]=rand();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
e[i]+=1ll*d[j]*a[j][i];
e[i]%=mod;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i]+=1ll*e[j]*b[j][i];
f[i]%=mod;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
g[i]+=1ll*d[j]*c[j][i];
g[i]%=mod;
}
}
for(int i=1;i<=n;i++){
if(f[i]!=g[i]){
flg=0;
break;
}
}
if(flg){
cout<<"Yes"<<'\n';
}else{
cout<<"No"<<'\n';
}
}
return Elaina;
}
T3 无标号 Multiset 构造
咕咕~
T4 有限制的构造
很巧妙的一个二维01背包,空间卡的死死的。
赛时糊了一个常规的二维背包,囍\(\color{purple}{RE}\)。
正解:
正常DP显然TLE,由于值域很大,即使优化掉一维,我们也开不了f[A][B]
那么大的数组,因此考虑间接推出答案。
吃 \(k\) 道菜,甜度不超过 \(j\) 时最小的咸度,只要这个最小咸度小于 \(Y\),那么就可以吃这 \(k\) 道菜,最后寻找符合条件的最大值。
转移方程:
可以倒序遍历优化掉一维。
int n,A,B,f[N][100];
struct NODE{
int a,b;
}p[N];
signed main(){
n=rd,A=rd,B=rd;
for(int i=1;i<=n;i++){
p[i].a=rd,p[i].b=rd;
}
memset(f,0x3f,sizeof(f));
for(int i=0;i<=A;i++){
f[i][0]=0;
}
for(int i=1;i<=n;i++){
for(int j=A;j>=p[i].a;j--){
for(int k=n;k;k--){
f[j][k]=min(f[j][k],f[j-p[i].a][k-1]+p[i].b);
}
}
}
for(int i=n;i>0;i--){
if(f[A][i]<=B){
printf("%d",min(n,i+1));
return 0;
}
}
printf("1");
return Elaina;
}