题面:https://www.cnblogs.com/Juve/articles/11663898.html
69:
本以为T2傻逼题结果爆零了。。。T3原题虽然打的不是正解复杂度但是都不记得做过这道题。。。
T1:组合数dp,发现i列与n+i列棋子个数一样,所以可以dp转移
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define int long long #define re register using namespace std; const int MAXN=105; const int mod=1e9+7; int n,m,c,ans=0,dp[MAXN][MAXN*MAXN]; int fac[MAXN],inv[MAXN],g[MAXN][MAXN]; inline int q_pow(re int a,re int b,re int p){ a%=p; re int res=1; while(b){ if(b&1) res=res*a%p; a=a*a%p; b>>=1; } return res%p; } void get_c(int N){ fac[0]=fac[1]=inv[0]=inv[1]=1; for(int i=2;i<=N;++i) fac[i]=fac[i-1]*i%mod; inv[N]=q_pow(fac[N],mod-2,mod); for(int i=N-1;i>=1;--i) inv[i]=inv[i+1]*(i+1)%mod; } int C(int n,int m){ if(n<m) return 0; if(n==m||m==0) return 1; return fac[n]*inv[m]%mod*inv[n-m]%mod; } signed main(){ scanf("%lld%lld%lld",&n,&m,&c); get_c(n); for(int i=0;i<=n;++i){ for(int j=0;j<=n;++j) g[i][j]=q_pow(C(n,i),(m-j)/n+1,mod)%mod; } dp[0][0]=1; for(int i=1;i<=n;++i){ for(int j=0;j<=min(n*i,c);++j) for(int t=0;t<=min(n,j);++t) dp[i][j]=(dp[i][j]+dp[i-1][j-t]*g[t][i]%mod)%mod; } printf("%lld ",dp[n][c]); return 0; }
array:
暴力思路:对于当前的位置i,在i前面找出第一个比a[i]大的位置j,然后在j到i中找最小值出现的位置就是i的答案
考虑优化,单调栈,维护单调递减的栈,每次pop时更新答案
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define int long long 6 #define re register 7 using namespace std; 8 const int MAXN=1e7+5; 9 inline int read(){ 10 re int x=0;re char ch=getchar(); 11 while(ch<'0'||ch>'9') ch=getchar(); 12 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();} 13 return x; 14 } 15 int n,a[MAXN],ans=0,sta[MAXN],top=0,pos[MAXN]; 16 signed main(){ 17 n=read();++n; 18 a[1]=0x7fffffff; 19 for(int i=2;i<=n;++i) a[i]=read(); 20 sta[++top]=1,pos[1]=1; 21 for(int i=2;i<=n;++i){ 22 pos[i]=i; 23 while(top&&a[i]>=a[sta[top]]){ 24 if(a[pos[i]]>=a[pos[sta[top]]]) 25 pos[i]=pos[sta[top]]; 26 --top; 27 } 28 sta[++top]=i; 29 ans=max(ans,i-pos[i]+1); 30 } 31 printf("%lld ",ans); 32 return 0; 33 }
70:
上来一看T1好像是高考数学,打了个表,发现的规律,然后A了,T3只会dfs搜索
T2一个可以优化成根号的dp,但是考场上状态定义错了,始终想不出转移,搜索又不好打,于是打了个40分骗分?
T1:
打表找规律,答案就是n的最大平方因子减一再乘上8
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define int long long using namespace std; int n,ans=0; signed main(){ while(~scanf("%lld",&n)){ if(n==0) break; int t=sqrt(n); for(int i=t;i>=1;--i){ if(n%(i*i)==0){ ans=i-1; break; } } printf("%lld ",8*ans); ans=0; } return 0; }
T2:
考虑dp,设f[i]表示前i个的最小贡献,枚举i,然后从i-1反向枚举j,统计i到j出现的多少数,记为x,则:
f[i]=min(f[j]+x2)
然后减枝,如果x2大于f[i]就break
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int MAXN=4e4+5; 8 int n,m,a[MAXN],f[MAXN],vis[MAXN]; 9 signed main(){ 10 scanf("%d%d",&n,&m); 11 for(int i=1;i<=n;++i) scanf("%d",&a[i]); 12 f[0]=0; 13 for(int i=1;i<=n;++i){ 14 f[i]=0x7fffffff; 15 vis[a[i]]=i; 16 int x=1; 17 for(int j=i-1;j>=0;--j){ 18 if(vis[a[j]]!=i){ 19 vis[a[j]]=i; 20 f[i]=min(f[i],f[j]+x*x); 21 if(x*x>=f[i]) break; 22 ++x; 23 } 24 } 25 } 26 printf("%d ",f[n]); 27 return 0; 28 }