这个题是计算不同子序列的和;
spoj上的那个同名的题是计算不同子序列的个数;
其实都差不多;
计算不同子序列的个数使用dp的思想;
从头往后扫一遍
如果当前的元素在以前没有出现过,那么dp[i]=dp[i-1]*2+1;
不然找到最右边的这个元素出现的位置j;
dp[i]=d[i]*2-dp[j];
spoj代码:
#include<cstdio> #include<cstring> #include<algorithm> #define mod 1000000007 using namespace std; char s[100005]; int pos[100005]; int biao[30]; int dp[100005]; int main() { int t,n; scanf("%d",&t); while(t--) { memset(biao,0,sizeof biao); scanf("%s",s+1); n=strlen(s+1); for(int i=1; i<=n; i++) { pos[i]=biao[s[i]-'A']; biao[s[i]-'A']=i; } dp[0]=0; for(int i=1; i<=n; i++) { if(pos[i]==0) { dp[i]=(dp[i-1]*2+1); while(dp[i]>=mod)dp[i]-=mod; } else { dp[i]=(dp[i-1]*2-dp[pos[i]-1]); if(dp[i]<0)dp[i]+=mod; while(dp[i]>=mod)dp[i]-=mod; } } printf("%d ",dp[n]+1); } return 0; }
csuoj代码:
#include<cstdio> #include<cstring> #include<algorithm> #define mod 1000000007 using namespace std; char s[100005]; int pos[100005]; int biao[15]; int dp[100005]; long long sum[100005]; int main() { int t,n; scanf("%d",&t); while(t--) { memset(biao,0,sizeof biao); scanf("%s",s+1); n=strlen(s+1); for(int i=1; i<=n; i++) { pos[i]=biao[s[i]-'0']; biao[s[i]-'0']=i; } dp[0]=0; for(int i=1; i<=n; i++) { long long tmp=sum[i-1]; if(pos[i]==0) { dp[i]=dp[i-1]*2; if((s[i]-'0')>0)dp[i]+=1; while(dp[i]>=mod)dp[i]-=mod; } else { dp[i]=(dp[i-1]*2-dp[pos[i]-1]); tmp-=sum[pos[i]-1]; if(tmp<0)tmp+=mod; if(dp[i]<0)dp[i]+=mod; while(dp[i]>=mod)dp[i]-=mod; } sum[i]=(tmp*10+(long long)(dp[i]-dp[i-1])*(s[i]-'0')+sum[i-1])%mod; if(sum[i]<=0)sum[i]+=mod; } printf("%lld ",sum[n]); } return 0; }