得分:
t1 100pts
t2 100pts
t3 保林(爆零)
rk#8(初二巨佬真的太强了)Dy Dy Ti 镪 仂
t1 公交换乘
/*一维动归简单不多说*/
#include <bits/stdc++.h>
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define INF 0x3f3f3f3f
using namespace std;
int a[15],dis,dp[300];
int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main()
{
rep(i,1,10)
a[i]=read();
dis=read();
memset(dp,127,sizeof(dp));
dp[0]=0;
rep(i,1,10)
rep(j,i,dis)
dp[j]=min(dp[j],dp[j-i]+a[i]);
printf("%d",dp[dis]);
return 0;
}
t2 数字矩形
/*
1.坑点还是有,代码里有注释
2.思维难度不是很大,维护ans的时候卡了一下*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
int n,m;
int dp[110][510],w[110][510];
int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main()
{
n=read(),m=read();
rep(i,1,n)
rep(j,1,m)
w[i][j]=read();
rep(i,1,n)
{
rep(j,1,m)//向下
dp[i][j]=dp[i-1][j]+w[i][j];
dwn(j,m-1,1)//向左,要先维护出右边!
dp[i][j]=min(dp[i][j],dp[i][j+1]+w[i][j]);
rep(j,2,m)//向右,要从2开始!!j-1>=0
dp[i][j]=min(dp[i][j],dp[i][j-1]+w[i][j]);
}
int ans=dp[n][m];
dwn(j,m-1,1)
ans=min(ans,dp[n][j]);
printf("%d",ans);
return 0;
}
t3 排列
/*注意以下几点:
1.读字符串我习惯从1开始读;
2.把一个串里的每个数字存下来的技巧见******1*******;
3.S&(1<<(j-1))表示S和第j-1位的数字是否相同(是否是1);
S|(1<<(j-1))表示把S的第j-1位修改为1;
4.(k*10+a[j])表示计算除法中的下一位;
5.注意去重的问题,我这里是使用了标记数组;
6.注意dp[0][0]=1;//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
but ouyangjz推荐的去重方式见下面的一个代码;
*/
#include<bits/stdc++.h>
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define N 11
using namespace std;
int T,mod,len;
int a[N],cnt,dp[1<<N][1002];
bool b[N];
char s[N];
int main()
{
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof(dp));
scanf("%s%d",s+1,&mod);
len=strlen(s+1);
cnt=0;
rep(i,1,len)
a[i]=s[i]-'0';//把所有数字存一下******1*******
dp[0][0]=1; //赋初值
rep(S,0,(1<<len)-1) //S表示当前所选的状态集合
{
memset(b,0,sizeof(b)); //注意清零
rep(j,1,len)
if(!(S&(1<<(j-1)))&&!b[a[j]])//如果a[j]已经转移过就不能继续转移了,j表示遍历s中的各位数字。
{
b[a[j]]=1;
rep(k,0,mod-1) //k表示对mod取余后的数
dp[S|(1<<(j-1))][(k*10+a[j])%mod]+=dp[S][k];
}
}
printf("%d
",dp[(1<<len)-1][0]);
}
return 0;
}
贴一个ouyang的代码
/*
去重:用全排列去重
*/
#include <cstdio>
#include <cstring>
char s[15];
int l,dp[5000][1005],f[15];
int main()
{
// freopen("perm.in","r",stdin);
// freopen("perm.out","w",stdout);
int t,maxn,ans,mod;
scanf("%d",&t);
while(t--)
{
scanf("%s",s);
l=strlen(s);
scanf("%d",&mod);
for(int i=0; i<l; i++)
f[i]=s[i]-'0';
maxn=1<<l;
for(int i=0; i<maxn; i++)
for(int j=0; j<mod; j++)
dp[i][j]=0;
dp[0][0]=1;
for(int i=0; i<maxn; i++)
for(int k=0; k<mod; k++)
if(dp[i][k])
{
for(int j=0; j<l; j++)
if((i&(1<<j))==0)
dp[i|(1<<j)][(k*10+f[j])%mod]+=dp[i][k];
}
ans=dp[maxn-1][0];
int x,r;
for(int i=0; i<10; i++)
{
x=0;
for(int j=0; j<l; j++)
if(f[j]==i)x++;
r=1;
for(int j=1; j<=x; j++)
r=r*j;
ans=ans/r;
}
printf("%d
",ans);
}
return 0;
}
UPD:粘一个LRL大佬的板子
我改了一点点……大佬代码的可读性就是要比我这种蒟蒻弱一点……
#define ll long long
#define rep(i,a,b) for(register int i=(a);i<=(b);++i)
#include<bits/stdc++.h>
using namespace std;
const int N=5055;
const int M=2055;
const int inf=0x3f3f3f3f;
char s[555];
ll cnt[15],a[15],mod,f[N][1055],ans;
ll jiecheng(ll x)
{
if(x==1||x==0)return 1;
ll ret=1;
rep(i,2,x)ret*=i;
return ret;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s %lld",s,&mod);
int len=strlen(s);
memset(cnt,0,sizeof(cnt));
rep(i,0,len-1)
{
a[i]=s[i]^48;
cnt[a[i]]++;
}
int maxs=(1<<len)-1;
rep(i,0,maxs)
rep(j,0,mod-1)
f[i][j]=0;
f[0][0]=1;
rep(i,0,maxs)//注意递推顺序,先确定k可以避免超时就超时
rep(k,0,mod-1)
if(f[i][k])
rep(j,0,len-1)
if((i&(1<<j))==0)
f[i|(1<<j)][(k*10+a[j])%mod]+=f[i][k];
ans=f[maxs][0];
rep(i,0,9)
ans/=jiecheng(cnt[i]);
printf("%lld
",ans);
}
return 0;
}