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));
}
}
}