T1:蒜头君的兔子
首先考虑暴力算法:用数组完全模拟,作为对拍程序:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MOD 1000000007
#define ll long long
using 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 12
using 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[i−1]∣ + \sum | r[i]-r[i-1] | \le∑∣r[i]−r[i−1]∣≤ 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 30005
using 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 30005
using 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;
}