1.26 动归赛总结

得分:

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\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;
}
posted @ 2019-10-08 15:27  设计涉及社稷  阅读(115)  评论(0编辑  收藏  举报