http://acm.zju.edu.cn/onlinejudge/showContestProblems.do?contestId=339
为了做浙大月赛,洗澡都没有去成,哎要等到下个星期三才能洗成吧!比完赛立马写解题报告,可以涨涨访问量把!
A题:
思路:枚举全是2 和 5 为素因子组成的数形如 2^a*5^b,然后判断他们的max(a,b) 是否下于等于 2^a*5^b 用十进制表示的位数即可因为10=2*5
代码:
#include <iostream> #include <cstdio> #include <cmath> using namespace std; int abs(int a) { return a<0?-a:a; } int solve(long long n) { long long ans=0,dd=1; int bit=(int)(log10(n*1.0)+1.0000001); // cout<<n<<" "<<bit<<endl; for(int n1=0;dd<=n&&n1<=bit; dd*=2,n1++) { long long tmp=1; int cnt=0; for(int n2=0;tmp*dd<=n&&n2<=bit;n2++,tmp*=5) cnt+=(max(n1,n2)<=(int)(log10(tmp*1.0*dd)+1.0000001)); //cout<<dd<<" dd "<<cnt<<endl; ans+=cnt; } return ans; } int main() { long long n,m; while(cin>>m>>n) { cout<<solve(n)-solve(m-1)<<endl; } return 0; }
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; int a[30]; int N,M,ans; void dfs(int id,int sum) { if(ans==M) return; if(ans<sum) ans=sum; for(int i=id;i<N&&a[i]+sum<=M;i++) { dfs(i+1,sum+a[i]); } } int main() { long long tot; while(scanf("%d%d",&N,&M)==2) { tot=0; for(int i=0;i<N;i++) scanf("%d",a+i),tot+=a[i]; if(tot<=M) { printf("%lld\n",tot); continue; } sort(a,a+N); ans=0; dfs(0,0); printf("%d\n",ans); } return 0; }
#include <iostream> #include <cstdio> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn=500010; typedef long long ll; const ll inf=9999999999999LL; ll d[maxn*4]; void build(int l,int r,int rt) { d[rt]=inf; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void update(int p,ll val,int l,int r,int rt) { if(l==r) { d[rt]=min(d[rt],val); return; } int m=(l+r)>>1; if(p<=m) update(p,val,lson); else update(p,val,rson); d[rt]=min(d[rt<<1],d[rt<<1|1]); } ll query(int L,int R,int l,int r,int rt) { if(L<=l&&R>=r) return d[rt]; int m=(l+r)>>1; ll ret1=inf,ret2=inf; if(L<=m) ret1=query(L,R,lson); if(R>m) ret2=query(L,R,rson); return min(ret1,ret2); } int day[maxn],cost[maxn]; int main() { int n; while(scanf("%d",&n)==1) { for(int i=1;i<=n;i++) scanf("%d",&cost[i]); for(int i=1;i<=n;i++) { scanf("%d",&day[i]); if(day[i]>n) day[i]=n; } build(1,n,1); update(day[1],cost[1],1,n,1); for(int i=2;i<=n;i++) { ll Min=query(i-1,n,1,n,1); int pos=i-1+day[i]; if(pos>n) pos=n; //cout<<Min<<endl; update(pos,Min+cost[i],1,n,1); } printf("%lld\n",query(n,n,1,n,1)); } return 0; } /* 4 10 20 1 40 3 2 3 1 */
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn=110; int n,val[maxn]; int map[maxn][maxn]; int dp[maxn][2*maxn],M; void dfs(int u,int fa) { dp[u][0]=val[u]; int tmp[2*maxn]={0}; for(int v=1;v<=n;v++) if(map[u][v]&&v!=fa) { dfs(v,u); //cout<<v<<" "<<map[u][v]<<endl; for(int i=0;i<=M;i++) for(int j=0;i+j+2*map[u][v]<=M;j++) tmp[i+j+2*map[u][v]]=max(tmp[i+j+2*map[u][v]],dp[u][i]+dp[v][j]); for(int i=0;i<=M;i++) dp[u][i]=max(dp[u][i],tmp[i]),tmp[i]=0; } } int main() { int a,b,c; while(scanf("%d",&n)==1) { for(int i=1;i<=n;i++) scanf("%d",val+i); memset(map,0,sizeof(map)); memset(dp,0,sizeof(dp)); for(int i=1;i<n;i++) { scanf("%d %d %d",&a,&b,&c); map[a][b]=map[b][a]=c; } int start; scanf("%d%d",&start,&M); dfs(start,-1); int ans=0; for(int i=0;i<=M;i++) ans=max(ans,dp[start][i]); printf("%d\n",ans); } return 0; }
PS:
H 题我找到规律了,但是就是wa,为什么结果用我暴力程序的结果对拍都对呀,不懂得为什么wa,泪……
B题 看到好多人都过了,我就是不知道怎么dp,想用搜索水过过去,但是不是wa就是TLE,泪……明明好多人都过了
B题原来就是01背包就行了,很巧妙的样子,想别人要的代码,谢谢别人的代码
#include<iostream> #include<stdio.h> #include<stdio.h> #include<cstring> using namespace std; int ti[40]; int wi[40]; int dp[350]; int N,L; int ma(int a,int b) { return a > b ? a: b; } int main( ) { int i,j,max; while( scanf("%d%d",&N,&L) != EOF ) { memset(ti,0,sizeof(ti)); memset(wi,0,sizeof(wi)); for( i = 0; i < 350; i++ ) dp[i] = 0; for( i = 1; i <= N; i++ ) scanf("%d%d",&ti[i],&wi[i]); max = 999999999; for( i = 1; i <= N; i++ ) { for( j = 1; j <= 330; j++ ) { dp[ti[i]+j] = ma( dp[ti[i]+j],dp[j] + wi[i]*j ); if( dp[j] >= L && max > j ) max = j; } } cout<<max<<endl; } //system("pause"); return 0; }
Treasure Hunt IV
当时比赛的时候没有做出来,隔几天之后再想想发现是个水题呀!原因就是当时虽然也找到规律了,但是没有想好,就一直在哪儿调试……悲剧
规律我都不说了,很容易找到的
#include <iostream> #include <cstdio> #include <cmath> using namespace std; typedef long long ll; ll solve(ll n) { if(n<0) return 0; ll ret=(ll)(sqrt(n*1.0)+0.00000001); ll ans=0; if(ret%2==0) ans+=n-ret*ret+1,ret--; ans+=ret*(ret+1)/2; return ans; } int main() { ll a,b; while(scanf("%lld %lld",&a,&b)==2) { printf("%lld\n", solve(b) - solve(a-1)); //cout<< solve(b) <<endl; } return 0; }
C 题 Count Path pair 组合数学公式就是( C(m + n, n) * C(m + q - p, q) - C(m + q, q) * C(n + m - p, n)) % 100000007 ,然后利用欧拉函数求逆元即可
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; const int mod=100000007; ll quick_pow(ll a,ll b) { ll ans=1; while(b) { if(b&1) ans=ans*a%mod; b>>=1; a=a*a%mod; } return ans; } int main() { ll n,m,p,q; while(scanf("%lld %lld %lld %lld",&m,&n,&p,&q)==4) { ll ans1=1,ans2=1,ans3=1,ans4=1; for(ll i=0;i<n;i++) ans1=ans1*(m+n-i)%mod; for(ll i=0;i<q;i++) ans2=ans2*(m-p+q-i)%mod; for(ll i=0;i<m;i++) ans3=ans3*(m+q-i)%mod; for(ll i=0;i<n;i++) ans4=ans4*(m-p+n-i)%mod; ll tmp1=1,tmp2=1,tmp3=1; for(int i=0;i<n;i++) tmp1=tmp1*(n-i)%mod; for(int i=0;i<q;i++) tmp2=tmp2*(q-i)%mod; for(int i=0;i<m;i++) tmp3=tmp3*(m-i)%mod; ans1=ans1*quick_pow(tmp1,mod-2)%mod; ans2=ans2*quick_pow(tmp2,mod-2)%mod; ans3=ans3*quick_pow(tmp3,mod-2)%mod; ans4=ans4*quick_pow(tmp1,mod-2)%mod; ll ans=(ans1*ans2%mod - ans3*ans4%mod)%mod; printf("%lld\n",(ans+mod)%mod); } return 0; }