E
TLE的方法:【也是现场赛卡住陆神的方法,状态n^2 决策n 结果悲剧的TLE了,semilive的时候我们也用的这个方法,MLE了。。。】
当时犯了致命的错误,以为优化了转移代价就可以降低复杂度,结果发现决策也是n的。
对于一个含 I 、 D 、 ?的链,遇到?号就断链 ,然后是对于无?的序列, 可以考虑成是某个前一个序列插入一个最大值,这个最大值只能出现最在极大值,和边界上。。
#include <cstdio> #include <string> #include <cstring> #include <iostream> typedef long long ll; using namespace std; const int maxn=1020; const ll mod=1000000007ll; char str[maxn]; ll com[maxn][maxn]; ll DP[maxn*maxn]; int n; int qmark[maxn];//以i为起点向后遇到的第一个问号的位置 int IDmark[maxn];//以i为起点向后遇到的第一个ID序列的I的位置 void init() { com[0][0]=1; com[1][0]=1; com[1][1]=1; for (int i=2 ; i<maxn-1 ; ++i) { com[i][0]=1; for (int j=1 ; j<=i; ++j) com[i][j]=(com[i-1][j]+com[i-1][j-1])%mod; //,printf(" i j %d %d %d\n" , i , j , com[i][j]); } } ll dp(int sta) { if(sta<0)return 1ll; ll ans = 0; int x=sta%n , y=sta/n; if(y>=n)return 1ll; if(x>y)return 1ll; int len=y-x+1; //printf("sta=%d x=%d y=%d len=%d\n" ,sta, x , y , len); if(DP[sta])return DP[sta]; if(len==1 && str[x]!='?')return DP[sta]=1ll; if(len==1 && str[x]=='?')return DP[sta]=2ll; /* for (int i=0 ; i<len ; ++i) { if(str[i]=='?') { //printf("%I64d\n",dp(ss.substr(0,i))); ans += (dp(0,i)*dp(ss.substr(i+1,len))%mod*com[len+1][i+1]%mod); return DP[strmap[ss]]=(ans == 0? 1:ans); } } */ int &j=qmark[x]; if(~j && j<=y) { //printf(" %d %d ??? %d %d\n",x,y,j,j-x+1); ans=(dp((j-1)*n+x)*dp(y*n+j+1)%mod*com[len+1][j-x+1]%mod); return DP[sta]=ans; } int p=IDmark[x]; while ((~p) && p<y) { //printf("p===%d\n",p); //printf("%d==\n",(p-1)*n+x); //printf("%d %d==\n",len,p-x+1); //printf("com==%lld\n",com[len][p-x+1]); ans=(ans+(dp((p-1)*n+x)*dp(y*n+p+2)%mod*com[len][p-x+1]%mod))%mod; p=IDmark[p+1]; } if(str[x]=='D')ans=(ans+dp(y*n+x+1))%mod; if(str[y]=='I')ans=(ans+dp((y-1)*n+x))%mod; return DP[sta]=(ans==0?1:ans)%mod; /* for (int i=0 ; i<len-1 ; ++i) { if(ss[i]=='I' && ss[i+1]=='D') { ans += (dp(ss.substr(0,i))*dp(ss.substr(i+2,len))%mod*com[len][i+1]%mod); } } if(ss[len-1]=='I')ans+=dp(ss.substr(0,len-1)); return DP[strmap[ss]]=(ans == 0? 1:ans); */ } int main() { init(); while (~scanf("%s",str)) { memset (DP , 0 , sizeof(DP)); memset (qmark , -1 , sizeof(qmark)); memset (IDmark , -1 , sizeof(IDmark)); n=strlen(str); for (int i=0 ; i<n ; ++i) { if(str[i]=='?') { int q=i; while (qmark[q]==-1 && q>=0) { qmark[q]=i; q--; } } if(i<n-1) { if(str[i]=='I' && str[i+1]=='D') { int q=i; while (IDmark[q]==-1 && q>=0) { IDmark[q]=i; q--; } } } } //for (int i=0 ; i<n ; ++i) //printf("qmark==%d IDmark==%d\n", qmark[i], IDmark[i]); printf("%lld\n",dp((n-1)*n+0)%mod);//rear * n+head ; } return 0; }
AC的方法:状态n^2 , 时间o(n^2) ,空间o(n)。
DP[i][j]表示剩余i个数 , 有j个数比当前数小
#include <cstdio> #include <cstring> const int maxn=1005; const int mod=1000000007; char str[maxn]; int dp[2][maxn];//剩下有j个比i位上的 int sum[2][maxn]; int main () { while (~scanf("%s",str)) { int n=strlen(str); for (int i=0 ; i<=n ; ++i)dp[0][i]=1,sum[0][i]=i+1; int turn=1; for (int i=n-1 ; i>=0 ; --i , turn^=1) { memset (dp[turn] , 0 , sizeof(dp[turn])); for (int j=0 ; j<=i ; ++j) { if(str[n-i-1]!='D') { //for (int k=j+1 ; k<=i+1 ; ++k) //dp[i][j]+=dp[i+1][k]; dp[turn][j]=(dp[turn][j]+sum[turn^1][i+1]-sum[turn^1][j]+mod)%mod; } if(str[n-1-i]!='I') { //for (int k=0 ; k<=j ; ++k) //dp[i][j]+=dp[i+1][k]; dp[turn][j]=(dp[turn][j]+sum[turn^1][j])%mod; } sum[turn][j]=(j>0?sum[turn][j-1]+dp[turn][j]:dp[turn][j])%mod; } } /* for (int i=0 ; i<=n+1 ; ++i) { for (int j=0 ; j<=n+1 ; ++j) printf("sum[%d][%d]==%lld " , i , j , sum[i][j]); printf("\n"); for (int j=0 ; j<=n+1 ; ++j) printf("dp[%d][%d]==%lld ", i , j ,dp[i][j]); printf("\n"); } */ printf("%d\n",dp[turn^1][0]%mod); } return 0; }
I题, 老朱用JAVA大数1Y了,我又用C的逆元敲了下
C代码:
#include <cstdio> #include <cstring> #include <cmath> typedef long long typen; typen mod=1000000007ll; /// typen x , y; typen eGCD(typen a , typen b ) { if(!b) { x=1 , y=0; return a; } int d=eGCD(b , a%b); int t=x; x=y; y=t-a/b*y; return d; } /// const int maxP=10005; int prime[maxP+1]; void getprime() { memset (prime , 0 , sizeof(prime)); for (int i=2 ; i<=maxP ; ++i) { if (!prime[i])prime[++prime[0]]=i; for (int j=1 ; j<=prime[0] && prime[j]*i<=maxP ; ++j) { prime[prime[j]*i]=1; if(i%prime[j]==0)break; } } } int factor[100][2]; int faccnt; void getFactors(int x) { faccnt=0; int tmp=x; for (int i=1 ; prime[i]*prime[i]<=tmp ; ++i) { factor[faccnt][1]=0; if(tmp%prime[i]==0) { factor[faccnt][0]=prime[i]; while (tmp%prime[i]==0) factor[faccnt][1]++,tmp/=prime[i]; ++faccnt; } } if(tmp != 1) factor[faccnt][0]=tmp , factor[faccnt++][1]=1; } /// int depth; typen inverse2 , inverse3 , inverse5 ; typen get_n4(typen x) { x=(x*x)%mod; return (typen)(x*x)%mod; } typen get_sigma_n4(typen n) { return ( inverse5*get_n4(n+1)%mod*(n+1)%mod -inverse5-inverse5*n%mod+mod+mod+mod -inverse2*(n*n%mod*(n+1)%mod*(n+1)%mod)%mod -inverse2*n%mod*(n+1)%mod+mod+mod+mod+mod -inverse3*n%mod*(n+1)%mod*(n<<1|1)%mod)%mod; } int n; typen ans; void dfs(int p , int cnt , int mul)//Exclusion Principle { if(p==depth) { if(cnt&1)ans=(ans-get_n4(mul)*get_sigma_n4(n/mul)%mod+mod)%mod; else ans=(ans+get_n4(mul)*get_sigma_n4(n/mul)%mod+mod)%mod; } /* printf("%d %d \n" , depth , cnt); printf("~!~! n4===%lld sigma==%lld %d\n" , get_n4(mul) , get_sigma_n4(n/mul) , n/mul); printf("ans==%lld mul==%d p==%d", ans , mul , p); printf(" f[%d]=%d" , p,factor[p][0]); printf("dfs(%d %d %d)\n",p , cnt ,mul ); */ else { dfs(p+1 , cnt+1 , mul*factor[p][0]); dfs(p+1 , cnt , mul); } } int main () { int cas; scanf("%d",&cas); getprime(); eGCD(2 , mod); inverse2=(x+mod)%mod; eGCD(3 , mod); inverse3=x; eGCD(5 , mod); inverse5=(x+mod)%mod; while (cas--) { scanf("%d",&n); getFactors(n); depth=faccnt; //printf("%lld\n",get_sigma_n4(n)); //printf("%lld\n",get_n4(n)); ans=0; dfs(0 , 0 , 1); printf("%d\n",ans%mod); } return 0; }
JAVA代码,以后学了JAVA 这个拿来当模板了:
import java.util.Scanner; import java.math.BigInteger; public class Main { /** * @param args the command line arguments */ static int prime[] = new int[10010]; static int getPrime() { for(int i = 0; i < 10010; ++ i) prime[i] = 0; for (int i = 2; i <= 10000; i++) { if (prime[i] == 0) prime[++prime[0]] = i; for (int j = 1; j <= prime[0] && prime[j]*i<= 10000; j++) { prime[prime[j]*i] = 1; if (i % prime[j] == 0) break; } } return prime[0]; } static int factor[][] = new int[100][3]; static int facCnt; static int getFactors(int x) { facCnt = 0; int tmp = x; for(int i = 1; prime[i] <= tmp / prime[i]; i++) { factor[facCnt][1] = 1; factor[facCnt][2] = 0; if(tmp % prime[i] == 0) factor[facCnt][0] = prime[i]; while(tmp % prime[i] == 0) { factor[facCnt][2]++; factor[facCnt][1] *= prime[i]; tmp /= prime[i]; } if(factor[facCnt][1] > 1) facCnt++; } if(tmp != 1) { factor[facCnt][0] = tmp; factor[facCnt][1] = tmp; factor[facCnt++][2] = 1; } return facCnt; } static BigInteger sumpower(int n){ BigInteger ret = BigInteger.valueOf(n); ret = (ret.multiply(ret.add(BigInteger.ONE)). multiply(ret.multiply(BigInteger.valueOf(2)).add(BigInteger.ONE)). multiply(BigInteger.valueOf(3).multiply(ret.multiply(ret)).add(BigInteger.valueOf(3).multiply(ret)).subtract(BigInteger.ONE))). divide(BigInteger.valueOf(30)); return ret.mod(modulo); } static BigInteger ans; static BigInteger modulo = new BigInteger("1000000007"); static void dfs(int idx, int fact,int cnt, int n) { if(idx == facCnt) { if(cnt % 2 == 1) ans = ans.subtract(BigInteger.valueOf(fact).pow(4).multiply(sumpower(n/fact))).add(modulo).mod(modulo); else ans = ans.add(BigInteger.valueOf(fact).pow(4).multiply(sumpower(n/fact))).mod(modulo); } else { dfs(idx+1, fact * factor[idx][0], cnt + 1, n); dfs(idx+1, fact , cnt, n); } } public static void main(String[] args) { Scanner scan = new Scanner(System.in); int t, n; getPrime(); t = scan.nextInt(); while(t-- > 0) { n = scan.nextInt(); getFactors(n); ans = BigInteger.ONE; dfs(0,1,0,n); System.out.println(ans.subtract(BigInteger.ONE).add(modulo).mod(modulo)); } } }