计蒜客 2017 NOIP 提高组模拟赛(一)Day2

来源:互联网 发布:jo malone推荐知乎 编辑:程序博客网 时间:2024/05/16 09:55

转送门

T1:蒜头君的兔子

首先考虑暴力算法:用数组完全模拟,作为对拍程序:

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#define MOD 1000000007#define ll long longusing namespace std;int n;ll a[15],b[15];int main(){    scanf("%d",&n);    ll sum=0;    a[1]=1;    for(int i=2;i<=n;i++){        memcpy(b+1,a,sizeof(ll)*10);        sum=((sum-a[10]+MOD)%MOD+a[1])%MOD;        b[0]=sum;        memcpy(a,b,sizeof(b));    }    sum=0;    for(int i=0;i<10;i++){        sum=(sum+b[i])%MOD;    }    printf("%lld\n",sum);    return 0;}

可以过6/7的数据

进一步考虑递推式:

d[i][j]表示第i天年龄为j岁兔子数目

那么有d[i][1]=d[i-1][1]+d[i-1][2]+……+d[i-1][9]
d[i][j]=d[i-1][j-1]
考虑矩阵快速幂优化
对于d[i][1]是一个9阶递推式
于是可以:
设初始状态为:
矩阵A=(0 1 0 0 0 0 0 0 0 0 0)
B=
(0 1 0 0 0 0 0 0 0 0 0
1 0 1 0 0 0 0 0 0 0 0
1 0 0 1 0 0 0 0 0 0 0
1 0 0 0 1 0 0 0 0 0 0
1 0 0 0 0 1 0 0 0 0 0
1 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 1 0 0 0
1 0 0 0 0 0 0 0 1 0 0
1 0 0 0 0 0 0 0 0 1 0
1 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 )
第二年为A*B
第三年为A*B^2
第n年为A*B^(n-1)
用快速幂优化,时间复杂度为O(1000*logn)

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#define MOD 1000000007#define ll long long#define MAXN 12using namespace std;struct Mat{int x,y;ll a[MAXN][MAXN];Mat(){x=y=0;memset(a,0,sizeof(a));}};int n;Mat cheng(Mat A,Mat B){Mat ret;ret.x=A.x,ret.y=B.y;for(int i=0;i<=ret.x;i++){for(int j=0;j<=ret.y;j++){for(int k=0;k<=ret.y;k++){ret.a[i][j]=(ret.a[i][j]+(A.a[i][k]*B.a[k][j])%MOD)%MOD;}}}return ret;}Mat power(Mat A,int p){if(1==p){return A;}if(p&1){return cheng(power(cheng(A,A),p>>1),A);}else{return power(cheng(A,A),p>>1);}}int main(){int n;scanf("%d",&n);Mat A,B;A.x=0; A.y=10;B.x=10; B.y=10;A.a[0][1]=1;for(int i=1;i<=9;i++){B.a[i][0]=1;}for(int i=0;i<=9;i++){B.a[i][i+1]=1;}if(n==1){printf("1\n");return 0;}Mat C=cheng(A,power(B,n-1));ll ans=0;for(int i=0;i<C.y;i++){ans=(ans+C.a[0][i])%MOD;}printf("%lld\n",ans);return 0;}
============================================

T2:蒜头君的排序

对于求冒泡排序的最小交换次数,就是求逆序对的个数
因为冒泡每次交换只能解决一对逆序对,所以至少交换次数为逆序对的数目
对于逆序对,可以用树状数组或者是分治,效率是O(nlogn)
这里很显然不能直接做,发现题目的提示l[i]l[i1] +\sum | r[i]-r[i-1] | \ler[i]r[i1]7×106

发现已知[L,R]可以很快速地算出[L,R+1] [L,R-1] [L+1,R] [L-1,R]

于是我们可以用莫队算法

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#include<cmath>#define MAXN 30005using namespace std;int n,m;int a[MAXN];int b1[MAXN],b2[MAXN];int sum1(int k){int ret=0;while(k>=1){ret+=b1[k];k-=(k&-k);}return ret;}void add1(int k,int x){while(k<=n){b1[k]+=x;k+=(k&-k);}}int sum2(int k){int ret=0;while(k<=n){ret+=b2[k];k+=(k&-k);}return ret;}void add2(int k,int x){while(k>=1){b2[k]+=x;k-=(k&-k);}}struct Qu{int L,R,Lb;int ans,id;Qu(){L=R=Lb=ans=0;}}s[MAXN];bool comp1(const Qu &p1,const Qu &p2){if(p1.Lb!=p2.Lb){return (p1.Lb<p2.Lb);}else{return (p1.R<p2.R);}}bool comp2(const Qu &p1,const Qu &p2){return (p1.id<p2.id);}int main(){//freopen("T2.in","r",stdin);//freopen("my.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}int len=sqrt((double)n);scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%d%d",&s[i].L,&s[i].R);s[i].id=i;s[i].Lb=s[i].L/len;}sort(s+1,s+m+1,comp1);int L=s[1].L,R=s[1].L-1,ans=0;for(int i=1;i<=m;i++){if(s[i].L!=L){if(L<s[i].L){for(int j=L;j<s[i].L;j++){ans-=sum1(a[j]-1);add1(a[j],-1);add2(a[j],-1);}}else{for(int j=L-1;j>=s[i].L;j--){ans+=sum1(a[j]-1);add1(a[j],1);add2(a[j],1);}}}if(s[i].R!=R){if(R>s[i].R){for(int j=R;j>s[i].R;j--){ans-=sum2(a[j]+1);add1(a[j],-1);add2(a[j],-1);}}else{for(int j=R+1;j<=s[i].R;j++){ans+=sum2(a[j]+1);add1(a[j],1);add2(a[j],1);}}}L=s[i].L,R=s[i].R;s[i].ans=ans;}sort(s+1,s+m+1,comp2);for(int i=1;i<=m;i++){printf("%d\n",s[i].ans);}return 0;}
顺便附上对拍程序:

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#define MAXN 30005using namespace std;int a[MAXN];int n;int main(){freopen("T2.in","r",stdin);freopen("std.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}int T;scanf("%d",&T);for(int k=1;k<=T;k++){int L,R;int ans=0;scanf("%d%d",&L,&R);for(int i=L;i<=R;i++){for(int j=i+1;j<=R;j++){if(a[i]>a[j]){ans++;}}}printf("%d\n",ans);}return 0;}
T3:蒜头君救人

一开始没有考虑到可以先接人送到终点后继续回来接人,结果WA

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#include<queue>#define MAXN 11#define MAXS 1<<11#define pii pair<int,int>using namespace std;int d[MAXS][MAXN][MAXN];int b[MAXS][MAXN][MAXN];int go[5]={0,1,0,-1,0};char a[MAXN][MAXN];int p[MAXN];int n,m,k,P;int sx,sy,tx,ty;queue<pii> q1;queue<int> q2;int SPFA(){memset(d,0x7f,sizeof(d));d[0][sx][sy]=0;b[0][sx][sy]=1;q1.push(make_pair(sx,sy));q2.push(0);while(!q1.empty()){int x=q1.front().first,y=q1.front().second;int S=q2.front();b[S][x][y]=0;q1.pop(); q2.pop();int w=k;for(int i=S,j=1;i;i>>=1,j++){if(i&1){w+=p[j];}} w=max(w,1);for(int k=0;k<4;k++){int dx=x+go[k],dy=y+go[k+1],dS=S;if(1<=dx&&dx<=n&&1<=dy&&dy<=m&&a[dx][dy]!='#'){if(1<=a[dx][dy]&&a[dx][dy]<=10){dS=(dS|(1<<(a[dx][dy]-1)));}if(d[dS][dx][dy]>d[S][x][y]+w){d[dS][dx][dy]=d[S][x][y]+w;if(!b[dS][dx][dy]){b[dS][dx][dy]=1;q1.push(make_pair(dx,dy));q2.push(dS);}}}}}return d[(1<<P)-1][tx][ty];}int main(){//freopen("T3.in","r",stdin);//freopen("my.out","w",stdout);scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){scanf(" %c",&a[i][j]);if('A'<=a[i][j]&&a[i][j]<='Z'){a[i][j]-=64;P=max(P,(int)a[i][j]);}else if('s'==a[i][j]){sx=i; sy=j;}else if('t'==a[i][j]){tx=i; ty=j;}}}for(int i=1;i<=P;i++){char c;scanf(" %c %d",&c,&p[i]);}printf("%d\n",SPFA());return 0;}
后来发现了这种情况,于是改为三进制数

1表示已经背上,2表示已经送走,0表示没有处理

对于到终点,可以考虑两种情况:

1)把消耗的人送走,把加快的人留下

2)全部送走(以获得最终答案)

时间复杂度约为O(3^P*n*m)

P为农民个数

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#include<queue>#define INF 0x7f7f7f7f#define MAXN 11#define MAXS 59050#define pii pair<int,int>using namespace std;int n,m,k;int a[MAXN][MAXN];int d[MAXS][MAXN][MAXN];int go[5]={0,1,0,-1,0};bool b[MAXS][MAXN][MAXN];queue<pii > q1;queue<int> q2;int sx,sy,tx,ty;int P,p[MAXN];int Power(int x,int k){int ret=1;for(int i=1;i<=k;i++){ret*=x;}return ret;}int main(){//freopen("T3.in","r",stdin);//freopen("my.out","w",stdout);scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){char c; scanf(" %c",&c);if('s'==c){sx=i; sy=j;a[i][j]=-1;}else if('t'==c){tx=i; ty=j;a[i][j]=-1;}else if('A'<=c&&c<='Z'){a[i][j]=c-64;P=max(P,a[i][j]);}else if('.'==c){a[i][j]=-1;}}}for(int i=1;i<=P;i++){char c;scanf(" %c %d",&c,&p[i]);}memset(d,0x7f,sizeof(d));d[0][sx][sy]=0;b[0][sx][sy]=1;q1.push(make_pair(sx,sy));q2.push(0);while(!q1.empty()){int x=q1.front().first,y=q1.front().second;int S=q2.front();b[S][x][y]=0;q1.pop(); q2.pop();int w=k;for(int t=S,L=1;t;t/=3,L++){if(1==(t%3)){w+=p[L];}}w=max(w,1);for(int k=0;k<4;k++){int dx=x+go[k],dy=y+go[k+1],dS=S;if(1<=dx&&dx<=n&&1<=dy&&dy<=m&&a[dx][dy]){if(dx==tx&&dy==ty){for(int t=S,L=1;t;t/=3,L++){if(1==(t%3)){dS+=Power(3,L-1);}}if(d[dS][dx][dy]>d[S][x][y]+w){d[dS][dx][dy]=d[S][x][y]+w;if(!b[dS][dx][dy]){b[dS][dx][dy]=1;q1.push(make_pair(dx,dy));q2.push(dS);}}if(dS==S){continue;}dS=S;for(int t=S,L=1;t;t/=3,L++){if(1==(t%3)&&p[L]>0){dS+=Power(3,L-1);}}if(d[dS][dx][dy]>d[S][x][y]+w){d[dS][dx][dy]=d[S][x][y]+w;if(!b[dS][dx][dy]){b[dS][dx][dy]=1;q1.push(make_pair(dx,dy));q2.push(dS);}}continue;}if(d[dS][dx][dy]>d[S][x][y]+w){d[dS][dx][dy]=d[S][x][y]+w;if(!b[dS][dx][dy]){b[dS][dx][dy]=1;q1.push(make_pair(dx,dy));q2.push(dS);}}if(a[dx][dy]>0){int t=S;for(int i=1;i<a[dx][dy];i++){t/=3;}t=t%3;if(!t){dS=S+Power(3,a[dx][dy]-1);if(d[dS][dx][dy]>d[S][x][y]+w){d[dS][dx][dy]=d[S][x][y]+w;if(!b[dS][dx][dy]){b[dS][dx][dy]=1;q1.push(make_pair(dx,dy));q2.push(dS);}}}}}}}int t=Power(3,P)-1;//for(int k=0;k<=t;k++){//for(int c=k,L=0;L<=5;c/=3,L++){//printf("%d ",c%3);//}//printf("\n");//for(int i=1;i<=n;i++){//for(int j=1;j<=m;j++){//if(INF==d[k][i][j]){//printf("- ");//}//else{//printf("%d ",d[k][i][j]);//}//}//printf("\n");//}//printf("\n");//}printf("%d\n",d[t][tx][ty]);return 0;}
顺便附上对拍程序

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#include<queue>#define INF 0x7f7f7f7f#define MAXN 11#define MAXS 1<<11#define pii pair<int,int>using namespace std;int d[MAXS][MAXN][MAXN];int go[5]={0,1,0,-1,0};char a[MAXN][MAXN];int p[MAXN];int n,m,k,P;int sx,sy,tx,ty;int ans=INF;void dfs(int S,int x,int y,int dep){if(d[S][x][y]<=dep){return;}d[S][x][y]=dep;if(S==(1<<P)-1&&x==tx&&y==ty){ans=min(ans,dep);}int w=k;for(int i=S,j=1;i;i>>=1,j++){if(i&1){w+=p[j];}} w=max(w,1);for(int k=0;k<4;k++){int dx=x+go[k],dy=y+go[k+1],dS=S;if(1<=dx&&dx<=n&&1<=dy&&dy<=m&&a[dx][dy]!='#'){if(1<=a[dx][dy]&&a[dx][dy]<=10){dS=(dS|(1<<(a[dx][dy]-1)));}dfs(dS,dx,dy,dep+w);}}}int main(){freopen("T3.in","r",stdin);freopen("std.out","w",stdout);scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){scanf(" %c",&a[i][j]);if('A'<=a[i][j]&&a[i][j]<='Z'){a[i][j]-=64;P=max(P,(int)a[i][j]);}else if('s'==a[i][j]){sx=i; sy=j;}else if('t'==a[i][j]){tx=i; ty=j;}}}for(int i=1;i<=P;i++){char c;scanf(" %c %d",&c,&p[i]);}memset(d,0x7f,sizeof(d));dfs(0,sx,sy,0);printf("%d\n",ans);return 0;}


原创粉丝点击