zoj4060
思维题目+找规律,比较难想!
划分不同块,找不同块。
根据不同块的数目又分为4种情况。(划分块就够难想了,这4种情况计算规律更是难找!)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 typedef long long ll; 6 ll n; 7 string s,t; 8 9 int main() 10 { 11 ios::sync_with_stdio(0); cin.tie(0); 12 13 int T; 14 cin>>T; 15 while(T--) 16 { 17 cin>>n>>s>>t; 18 int cnt=0; 19 for(int i=0;i<n;i++) 20 { //i=0是有单个字符这种特殊情况 21 if((i==0 || s[i-1]==t[i-1]) && s[i]!=t[i]) cnt++; 22 } 23 24 if(cnt>2) cout<<"0"<<endl; 25 else if(cnt==2) cout<<"6"<<endl; 26 else if(cnt==1) cout<<ll(2*n-2)<<endl; 27 else cout<<ll(n*(n+1)/2)<<endl; 28 } 29 }
Plants vs. Zombies,zoj4062
最小值最大化,典型的二分答案
关键是judge函数怎么写
除此之外,写出judge也很难ac,此题尽是坑点,写的我一把辛酸泪啊QAQ~~
什么最后一个要特判,不加次数。。
什么很容易超ll。。
什么负数。。
什么超时。。
都要及时跳出才行
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 typedef long long ll; 6 const int maxn=1e5+10; 7 8 int n; 9 ll m; 10 ll a[maxn],d[maxn]; 11 12 ll judge(ll k) 13 { 14 //memset(d,0,(n+1)*sizeof(ll)); 15 //memset(d,0,sizeof(d));//1520ms 16 for(int i=0;i<=n+1;i++) d[i]=0;//630ms 17 18 ll cnt=0; 19 for(int i=1;i<=n;i++) 20 { 21 if(i==n && d[i]>=k) break;//坑点1,最后一个特判 22 23 cnt++; d[i]+=a[i];//注意这个细节,d[i]+=a[i]要放到continue前面,后面必错!(先把每一步必须的一步加上,不要和后面的放在一起算,不容易错) 24 if(d[i]>=k) continue;//坑点2,不要一直加,会超ll,同时关键防止了下面负数情况!! 25 //d[i]+=a[i];//之前以为放这一直错QAQ 26 27 ll c=(k-d[i])/a[i];//坑点3,这里(通过上面continue)要防止了过大变负数 28 if((k-d[i])%a[i]) c++; 29 cnt+=2*c; 30 d[i]+=c*a[i]; 31 d[i+1]+=c*a[i+1]; 32 33 if(cnt>m) break; 34 } 35 return cnt; 36 } 37 38 int main() 39 { 40 ios::sync_with_stdio(0); 41 cin.tie(0); 42 43 int T; 44 cin>>T; 45 while(T--) 46 { 47 cin>>n>>m; 48 ll mn=1e5+10; 49 for(int i=1;i<=n;i++) cin>>a[i], mn=min(mn,a[i]); 50 51 ll l=0, r=mn*m,ans=0; 52 while(l<=r) 53 { 54 ll mid=(l+r)>>1; 55 if(judge(mid)<=m) 56 { 57 ans=mid; 58 l=mid+1; 59 } 60 else r=mid-1; 61 } 62 cout<<ans<<endl; 63 } 64 }
Books,zoj4067
略难的贪心,分清楚3种情况即可(况且样例都给你了,解释的清清楚楚名明明白白QAQ)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 typedef long long ll; 6 const ll maxn=1e5+10; 7 const ll inf=1e9+5; 8 ll T,n,m; 9 ll a[maxn]; 10 11 int main() 12 { 13 ios::sync_with_stdio(0); cin.tie(0); 14 15 cin>>T; 16 while(T--) 17 { 18 cin>>n>>m; 19 ll cnt0=0; 20 for(int i=1;i<=n;i++) 21 { 22 cin>>a[i]; 23 if(a[i]==0) cnt0++; 24 } 25 26 if(m>=n) cout<<"Richman"<<endl; 27 else if(cnt0>m) cout<<"Impossible"<<endl; 28 else 29 { 30 m-=cnt0;//贪心肯定先选m为0的书籍 31 ll mn=inf,ans=0; 32 for(int i=1;i<=n;i++) 33 { 34 if(a[i]==0) continue;//因为为0的书籍已经挑过了,前面m-=cnt0! 35 36 if(m)//如果还有次数的话就选 37 { 38 ans+=a[i]; 39 m--; 40 } 41 else mn=min(mn,a[i]);//从没选过的剩下的里面选一个最小的 42 } 43 44 ans+=mn-1; 45 cout<<ans<<endl; 46 } 47 } 48 49 return 0; 50 }
Function and Function,zoj4070
签到题,给你的递归形式,但不要一条路到死。递归可以改循环,循环也可以改递归,哪个不爆栈方便用哪个。
做这题有2点:
1.做这题关键重点:把它的函数嵌套全部展开,g(x)就变成了次方个f(x)!!从头开始计算就行了。
2.然后是规律,k辣么大每次都算肯定超市啦,发现0和1的函数值相反正好来回跳,所以到0我们就可以根据剩余次方判断出答案啦!
(3.有个坑点很容易错,0的函数值是0,必须特判返回1。像其它一样取位正常算的话返回是0。很容易错)
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 typedef long long ll; 5 ll s[10]={1,0,0,0,1,0,1,0,2,1}; 6 ll T,x,k; 7 8 ll f(ll y) 9 { 10 if(y==0) return 1;//坑点,很重要,因为0特殊,下面返回0是错的! 11 12 ll ans=0; 13 while(y) 14 { 15 ans+=s[y%10]; 16 y/=10; 17 } 18 19 return ans; 20 } 21 22 int main() 23 { 24 //ios::sync_with_stdio(false); cin.tie(0); 25 26 scanf("%lld",&T); 27 while(T--) 28 { 29 scanf("%lld%lld",&x,&k); 30 31 if(k==0) { printf("%lld ",x); continue;} 32 33 for(int i=1;i<=k;i++) 34 { 35 x=f(x); 36 if(x==0) 37 { 38 ll t=k-i; 39 if(t%2) x=1; 40 else x=0; 41 break; 42 } 43 } 44 printf("%lld ",x); 45 } 46 47 return 0; 48 }
完。