第一题
简单模拟,把s拆成二进制形式,然后统计有多少个一,将 ans/n*m 化简即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<ctime> 7 #include<algorithm> 8 using namespace std; 9 long long n,m,s,ans; 10 inline long long read() 11 { 12 long long x=0,f=1; char ch=getchar(); 13 while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} 14 while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} 15 return x*f; 16 } 17 long long gcd(long long a,long long b) {return b==0?a:gcd(b,a%b);} 18 int main() 19 { 20 freopen("huajitree.in","r",stdin); 21 freopen("huajitree.out","w",stdout); 22 n=read(); m=read(); s=read(); 23 while(s) {if(s%2==1) ans++; s/=2;} 24 long long r=gcd(ans,n*m); 25 if(!ans) printf("0 "); 26 else printf("%I64d/%I64d ",ans/r,m*n/r); 27 return 0; 28 }
第二题
无力吐槽贪心水过,请看正解动态规划。
用sumv和sumh分别维护v和h的前缀和,f[i]表示将前i件物品放入背包的最小代价,那么很容易写出状态转移方程:f[i]=min{f[i],f[j]+sumh[i]*(sumv[i]-sumv[j])}
O(n^2)的时间复杂度,可以过掉60分,然后需要进行斜率优化。
假设从k转移到i比j更优,则有f[k]+sumh[i]*sumv[i]-sumh[i]*sumv[k]<f[j]+sumh[i]*sumv[i]-sumh[i]*sumv[j]
化简得(f[k]-f[j])/(sumv[k]-sumv[j])<sumh[i]
这就是斜率表达式了,然后维护凸包即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<ctime> 7 #include<algorithm> 8 #define MAXN 1000010 9 using namespace std; 10 long long n,f[MAXN],v[MAXN],h[MAXN],sumv[MAXN],sumh[MAXN],q[MAXN]; 11 inline long long read() 12 { 13 long long x=0,f=1; char ch=getchar(); 14 while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} 15 while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} 16 return x*f; 17 } 18 long long slop(long long a,long long b){return (f[a]-f[b])/(sumv[a]-sumv[b]);} 19 int main() 20 { 21 freopen("pack.in","r",stdin); 22 freopen("pack.out","w",stdout); 23 n=read(); 24 for(int i=1;i<=n;i++) 25 { 26 v[i]=read(); 27 h[i]=read(); 28 sumv[i]=v[i]+sumv[i-1]; 29 sumh[i]=h[i]+sumh[i-1]; 30 f[i]=sumv[i]*sumh[i]; 31 } 32 f[1]=v[1]*h[1]; 33 long long l=0,r=0; 34 for(int i=1;i<=n;i++) 35 { 36 while(l<r&&slop(q[l],q[l+1])<sumh[i])l++; 37 long long t=q[l]; 38 f[i]=f[t]+sumh[i]*(sumv[i]-sumv[t]); 39 while(l<r&&slop(q[r-1],q[r])>slop(q[r],i))r--; 40 q[++r]=i; 41 } 42 printf("%I64d ",f[n]); 43 return 0; 44 }
第三题
线段树维护图的连通性,考试时完全没有想到,写了一个暴力,然后挂了。
这题是bzoj1018原题。