• 洛谷 P1385 密令(dp,离线)


    传送门


    解题思路

    首先可以发现,无论怎么变,字母的和是不变的。
    而且每个位置是多少都行(只要和别超)。
    用dp[i][j]表示前i位的和为j的方案数。
    然后枚举第j位可能情况(0~25),从dp[i-1][j-k]转移过来即可。
    一种思路是先预处理这个dp数组,然后回答询问。
    另一种思路是离线处理,这样dp数组的第一维可以滚动掉,逆序枚举j,边求dp边存储答案。
    再就是开long long可以使取模运算放到最后,这样对于每个dp[i][j]只取模了一次。
    我用的第二种思路,没特意卡常(还用的关闭同步的cin、cout),交上去竟拿了个最优解。
    第二种思路复杂度应该为 (O(Tlog T+26 imes len_{max}sum_{max}))

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int mod=1e9+7;
    int T;
    long long dp[3005],m;
    string s;
    struct node{
    	int id;
    	long long len,sum,ans;
    }q[10005];
    bool cmp1(node a,node b){
    	return a.len<b.len;
    }
    bool cmp2(node a,node b){
    	return a.id<b.id;
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>T;
    	for(int t=1;t<=T;t++){
    		cin>>s;
    		q[t].id=t;
    		q[t].len=s.length();
    		for(int i=0;i<q[t].len;i++){
    			q[t].sum+=s[i]-'a';
    		}
    		m=max(m,q[t].sum);
    	}
    	sort(q+1,q+T+1,cmp1);
    	int now=1;
    	for(int i=0;i<=25;i++) dp[i]=1;
    	while(now<=T&&q[now].len==1){
    		q[now].ans=1;
    		now++;
    	}
    	for(int i=1;i<q[T].len;i++){
    		for(int j=m;j>=0;j--){
    			for(int k=1;k<=25;k++){
    				if(j<k) break;
    				dp[j]+=dp[j-k];
    			}
    			dp[j]%=mod;
    		}
    		while(now<=T&&q[now].len==i+1){
    			q[now].ans=dp[q[now].sum];
    			now++;
    		}
    	}
    	sort(q+1,q+T+1,cmp2);
    	for(int i=1;i<=T;i++){
    		cout<<q[i].ans-1<<endl;
    	}
        return 0;
    }
    
  • 相关阅读:
    l1-013
    将博客搬至CSDN
    Educational Codeforces Round 25
    大组合数取余模板【Lucas定理】
    Exams(二分求左界+贪心)
    Cutting (暴力 + 滚动哈希判字符串匹配)
    Cubes(DFS+剪枝)
    Codeforces Round #409 (Div. 2)
    【复习挖坑】dp + 图
    n & n-1 和 n & -n
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15336613.html
Copyright © 2020-2023  润新知