得分:

t1 100pts

t2 100pts

t3

rk#8(初二巨佬真的太强了)


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\n",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\n",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\n",ans);
    }
    return 0;
}
02-01 12:50
查看更多