2021-09-04模拟赛
今天爆零了,感觉很不应该,也许是没有进入状态,或者是有点飘了
首先在战略上我没有转到模拟得分战略,而是尝试先去切题,这和昨天讲的背道而驰
在战术上我没有及时转移
首先把题全都看一遍就应该意识到这次模拟不会那么简单,应该以得分为主以暴力为主,但是在看到T2的时候感觉自己能切,还是没忍住去写了链表,但是接近写完的时候才发现这么写的话IC操作时间复杂度是假的,不得已只能改变原有写法,利用现有代码写20分暴力,这期间debug耗了很长时间,但是就一直耗着,没有及时转移
接着我又没有去利用本来已经不多的时间去尽快写了暴力,而是费尽心思去想T1规律,花了很长时间找规律,导致时间已经不足以写完矩阵快速幂,就急急忙忙写了40分,这时才想起来去写T3T4暴力,但时间已经不够了
成绩出了之后,爆零了
下午仔细分析了一下,发现T3T4依然不太可做,但是T1T2应该能拿200
首先针对我研究了很长时间的T2链表做法
20分:
强行二维链表,记录每个点上下左右点的坐标,更新时分别维护横纵最值,输出时遍历即可
但是出问题了
经过大量的数据对拍,可以发现一个问题:当操作数大于矩阵边长的时候就没对过,那么为什么呢
单独上下操作或者左右操作都没有问题,那么问题就只可能出在输出上了,仔细看看输出,也没什么问题
那么是什么问题呢,我们可以发现,在矩阵边长以下的变换是正确的,并且输出进行的操作居然只有矩阵边长次
这是我就隐隐意识到不大对劲,估计是进行操作的时候出大问题
一看,不就是嘛,应该进行m次操作,循环上写的n
0分代码:
#include<bits/stdc++.h>
#define N 1005
#define M 1000005
#define ll long long
#define fn(i,st,ed) for(int i=st;i<=ed;i++)
#define fd(i,st,ed) for(int i=st;i>=ed;i--)
#define fg(i,x) for(int i=head[x];~i;i=e[i].nxt)
#define pa pair<int,int>
#define mkp(x,y) make_pair(x,y)
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
class Link_List{
public:
void build(int n){
fn(i,1,n)fn(j,1,n){
if(i==1){
if(j==1){
L[1][1]=mkp(1,n);
R[1][1]=mkp(1,2);
U[1][1]=mkp(n,1);
D[1][1]=mkp(2,1);
continue;
}
if(j==n){
L[1][n]=mkp(1,n-1);
R[1][n]=mkp(1,1);
U[1][n]=mkp(n,n);
D[1][n]=mkp(2,n);
continue;
}
L[1][j]=mkp(1,j-1);
R[1][j]=mkp(1,j+1);
U[1][j]=mkp(n,j);
D[1][j]=mkp(2,j);
continue;
}
if(i==n){
if(j==1){
L[n][1]=mkp(n,n);
R[n][1]=mkp(n,2);
U[n][1]=mkp(n-1,1);
D[n][1]=mkp(1,1);
continue;
}
if(j==n){
L[n][n]=mkp(n,n-1);
R[n][n]=mkp(n,1);
U[n][n]=mkp(n-1,n);
D[n][n]=mkp(1,n);
continue;
}
L[n][j]=mkp(n,j-1);
R[n][j]=mkp(n,j+1);
U[n][j]=mkp(n-1,j);
D[n][j]=mkp(1,j);
continue;
}
if(j==1){
L[i][1]=mkp(i,n);
R[i][1]=mkp(i,2);
U[i][1]=mkp(i-1,1);
D[i][1]=mkp(i+1,1);
continue;
}
if(j==n){
L[i][n]=mkp(i,n-1);
R[i][n]=mkp(i,1);
U[i][n]=mkp(i-1,n);
D[i][n]=mkp(i+1,n);
continue;
}
L[i][j]=mkp(i,j-1);
R[i][j]=mkp(i,j+1);
U[i][j]=mkp(i-1,j);
D[i][j]=mkp(i+1,j);
}
l=1,r=n,u=1,d=n;
}
void RC(){
l=L[1][l].second;
r=L[1][r].second;
}
void LC(){
l=R[1][l].second;
r=R[1][r].second;
}
void UC(){
u=D[u][1].first;
d=D[d][1].first;
}
void DC(){
u=U[u][1].first;
d=U[u][1].first;
}
protected:
pa L[N][N],R[N][N],U[N][N],D[N][N];
int a[N][N];
int l,r,u,d;
};
class solution:protected Link_List{
public:
void init(){
n=read(),m=read();
fn(i,1,n)fn(j,1,n)a[i][j]=read();
scanf("%s",operation);
build(n);
}
void solve(){
fn(i,0,n-1){//这里应该是m-1
if(operation[i]=='R')RC();
if(operation[i]=='L')LC();
if(operation[i]=='U')UC();
if(operation[i]=='D')DC();
}
for(int x=u,y;;){
for(y=l;;){
printf("%d ",a[x][y]);
if(y==r)break;
y=R[x][y].second;
}
printf("\n");
if(x==d)break;
x=D[x][y].first;
}
}
private:
int n,m;
char operation[M];
}S;
int main(){
freopen("mat.in","r",stdin);
freopen("mat.out","w",stdout);
S.init();S.solve();
return 0;
}
20分代码:
#include<bits/stdc++.h>
#define N 1005
#define M 1000005
#define ll long long
#define fn(i,st,ed) for(int i=st;i<=ed;i++)
#define fd(i,st,ed) for(int i=st;i>=ed;i--)
#define fg(i,x) for(int i=head[x];~i;i=e[i].nxt)
#define pa pair<int,int>
#define mkp(x,y) make_pair(x,y)
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
class Link_List{
public:
void build(int n){
fn(i,1,n)fn(j,1,n){
if(i==1){
if(j==1){
L[1][1]=mkp(1,n);
R[1][1]=mkp(1,2);
U[1][1]=mkp(n,1);
D[1][1]=mkp(2,1);
continue;
}
if(j==n){
L[1][n]=mkp(1,n-1);
R[1][n]=mkp(1,1);
U[1][n]=mkp(n,n);
D[1][n]=mkp(2,n);
continue;
}
L[1][j]=mkp(1,j-1);
R[1][j]=mkp(1,j+1);
U[1][j]=mkp(n,j);
D[1][j]=mkp(2,j);
continue;
}
if(i==n){
if(j==1){
L[n][1]=mkp(n,n);
R[n][1]=mkp(n,2);
U[n][1]=mkp(n-1,1);
D[n][1]=mkp(1,1);
continue;
}
if(j==n){
L[n][n]=mkp(n,n-1);
R[n][n]=mkp(n,1);
U[n][n]=mkp(n-1,n);
D[n][n]=mkp(1,n);
continue;
}
L[n][j]=mkp(n,j-1);
R[n][j]=mkp(n,j+1);
U[n][j]=mkp(n-1,j);
D[n][j]=mkp(1,j);
continue;
}
if(j==1){
L[i][1]=mkp(i,n);
R[i][1]=mkp(i,2);
U[i][1]=mkp(i-1,1);
D[i][1]=mkp(i+1,1);
continue;
}
if(j==n){
L[i][n]=mkp(i,n-1);
R[i][n]=mkp(i,1);
U[i][n]=mkp(i-1,n);
D[i][n]=mkp(i+1,n);
continue;
}
L[i][j]=mkp(i,j-1);
R[i][j]=mkp(i,j+1);
U[i][j]=mkp(i-1,j);
D[i][j]=mkp(i+1,j);
}
l=1,r=n,u=1,d=n;
}
void RC(){
l=L[1][l].second;
r=L[1][r].second;
}
void LC(){
l=R[1][l].second;
r=R[1][r].second;
}
void UC(){
u=D[u][1].first;
d=D[d][1].first;
}
void DC(){
u=U[u][1].first;
d=U[u][1].first;
}
protected:
pa L[N][N],R[N][N],U[N][N],D[N][N];
int a[N][N];
int l,r,u,d;
};
class solution:protected Link_List{
public:
void init(){
n=read(),m=read();
fn(i,1,n)fn(j,1,n)a[i][j]=read();
scanf("%s",operation);
build(n);
}
void solve(){
fn(i,0,m-1){
if(operation[i]=='R')RC();
if(operation[i]=='L')LC();
if(operation[i]=='U')UC();
if(operation[i]=='D')DC();
}
for(int x=u,y;;){
for(y=l;;){
printf("%d ",a[x][y]);
if(y==r)break;
y=R[x][y].second;
}
printf("\n");
if(x==d)break;
x=D[x][y].first;
}
}
private:
int n,m;
char operation[M];
}S;
int main(){
freopen("mat.in","r",stdin);
freopen("mat.out","w",stdout);
S.init();S.solve();
return 0;
}
100分:
显然对于上下和左右的操作,相反的操作是可以抵消的,而IC操作其实就是将权值与位置互换,我们可以设置一个状态,当出现IC操作的时候,我们转到这个状态上,之后的上下左右操作则需要在这个状态下进行记录,统计答案时则根据状态转移每个点
100分代码:
#include<bits/stdc++.h>
#define N 1005
#define M 1000005
#define ll long long
#define fn(i,st,ed) for(int i=st;i<=ed;i++)
#define fd(i,st,ed) for(int i=st;i>=ed;i--)
#define fg(i,x) for(int i=head[x];~i;i=e[i].nxt)
#define pa pair<int,int>
#define mkp(x,y) make_pair(x,y)
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
char operation[M],a[N][N],ans[N][N],now[4]={0,1,2,3},addition[4];
int main(){
int n=read(),m=read();
fn(i,1,n)fn(j,1,n)a[i][j]=read();
scanf("%s",operation+1);
fn(i,1,m){
char c=opeartion[i];
if(c=='R')add[now[2]]++;
if(c=='L')add[now[2]]--;
if(c=='D')add[now[1]]++;
if(c=='U')add[now[1]]--;
if(c=='I')swap(now[2],now[3]);
if(c=='C')swap(now[1],now[3]);
}
fn(i,1,n)fn(j,1,n){
int t[4]={0,i,j,a[i][j]};
fn(k,1,3)t[k]=((t[k]+add[k]-1)%n+n)%n+1;
ans[t[now[1]]][t[now[2]]]=t[now[3]];
}
fn(i,1,n){fn(j,1,n)printf("%d ",ans[i][j]);printf("\n");}
return 0;
}
对于T2,我们可以得出一点教训,不要相信样例,因为很水,自己出数据一定要出大一点,出的刁钻一点
接下来去看T1
T1我的递推式子是没有错的,那么问题会出在哪里呢,我一打开代码就看到了,我求出的递推值根本就没用到
0分代码:
#include<bits/stdc++.h>
#define M 10000005
#define mod 1000000007
#define ll long long
#define fn(i,st,ed) for(int i=st;i<=ed;i++)
#define fd(i,st,ed) for(int i=st;i>=ed;i--)
#define fg(i,x) for(int i=head[x];~i;i=e[i].nxt)
#define pa pair<int,int>
#define mkp(x,y) make_pair(x,y)
using namespace std;
inline ll read(){
ll x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
ll x[M],f[M],ans;
int main(){
//freopen("per.in","r",stdin);
//freopen("per.out","w",stdout);
f[1]=1,f[2]=1,f[3]=2,f[4]=4;
x[1]=x[2]=x[3]=x[4]=0;
fn(i,5,M-1){x[i]=x[i-1]+f[i-3];f[i]=(x[i]+i)%mod;}
int t=read();
while(t--){
ll x=read();
ans=ans^x;//这里出大问题
}
printf("%lld\n",ans);
return 0;
}
40分代码:
#include<bits/stdc++.h>
#define M 10000005
#define mod 1000000007
#define ll long long
#define fn(i,st,ed) for(int i=st;i<=ed;i++)
#define fd(i,st,ed) for(int i=st;i>=ed;i--)
#define fg(i,x) for(int i=head[x];~i;i=e[i].nxt)
#define pa pair<int,int>
#define mkp(x,y) make_pair(x,y)
using namespace std;
inline ll read(){
ll x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
ll x[M],f[M],ans;
int main(){
//freopen("per.in","r",stdin);
//freopen("per.out","w",stdout);
f[1]=1,f[2]=1,f[3]=2,f[4]=4;
x[1]=x[2]=x[3]=x[4]=0;
fn(i,5,M-1){x[i]=x[i-1]+f[i-3];f[i]=(x[i]+i)%mod;}
int t=read();
while(t--){
ll x=read();
ans=ans^f[x];
}
printf("%lld\n",ans);
return 0;
}
100分:
使用矩阵快速幂进行优化,没什么可说的,根本就是时间不够了
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
const int mod=1e9+7;
#define ll long long
int n,m;
ll f[N];
ll ans;
struct matrix{
ll a[5][5];
int x,y;
};
void print(matrix o){
printf("------\n");
for(int i=1;i<=o.x;i++){
for(int j=1;j<=o.y;j++) printf("%lld ",o.a[i][j]);
printf("\n");
}
printf("\n");
}
matrix mul(matrix u,matrix v){
matrix ans;
ans.x=u.x,ans.y=v.y;
for(int i=1;i<=ans.x;i++){
for(int j=1;j<=ans.y;j++){
ans.a[i][j]=0;
for(int k=1;k<=u.y;k++) ans.a[i][j]=(ans.a[i][j]+u.a[i][k]*v.a[k][j])%mod;
}
}
return ans;
}
int pre[5][5]={{},{0,1,0,0,0},{0,1,0,0,1},{0,0,1,0,0},{0,1,0,1,1}};
matrix tr;
matrix ksm(matrix o,int k){
matrix ans;
ans.x=ans.y=o.x;
for(int i=1;i<=o.x;i++)
for(int j=1;j<=o.x;j++) ans.a[i][j]=i==j;
while(k){
if(k&1) ans=mul(ans,o);
o=mul(o,o);
k>>=1;
}
return ans;
}
matrix lst;
int main(){
//freopen("per.in","r",stdin);
//freopen("per.out","w",stdout);
tr.x=tr.y=4;
for(int i=1;i<=4;i++){
for(int j=1;j<=4;j++) tr.a[i][j]=pre[i][j];
}
lst.x=1,lst.y=4;
lst.a[1][1]=3;lst.a[1][2]=1;lst.a[1][3]=1;lst.a[1][4]=1;
int T;
scanf("%d",&T);
ll tot=0;
while(T--){
ll oo;
scanf("%d",&n);
if(n==1) oo=1;
else if(n==2) oo=1;
else if(n==3) oo=2;
else{
matrix res=ksm(tr,n-3);
matrix ans=mul(lst,res);
oo=(ans.a[1][1]-ans.a[1][3]+mod)%mod;
}
tot^=oo;
}
printf("%lld",tot);
}
今天也算是一个时间节点吧,这次模拟可以给我一个比较深刻的教训
既然打算大量投入时间在竞赛上,就应该去认真对待,而不是这错一点小错误,那错一点小错误,时间上根本没进入模拟状态,应该每次模拟都认真对待,不要轻信样例,要多多自己去造数据,不要死扣一个题,先写暴力在想去切,每个题都尝试着写一写,不要连写都不写
这些问题以后都不要出现,不然是走不长远的