A.小乔和小灰灰:
直接暴力求解。
代码:
#include <bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; typedef pair<int,int>P; const int N=1010; char ss[N]; int main() { scanf("%s",ss+1); int len=strlen(ss+1); char s1[10]="XiaoQiao"; char s2[15]="XiaoHuiHui"; bool f1=0,f2=0; int p=0; for(int i=1;i<=len;i++) { if(ss[i]==s1[p]) p++; if(p==8) { f1=1; break; } } p=0; for(int i=1;i<=len;i++) { if(ss[i]==s2[p]) p++; if(p==10) { f2=1; break; } } if(f1&&f2) printf("Happy\n"); else printf("emm\n"); return 0; }
B.牛能和小镇:
一看是求最小生成树,直接开始一顿猛敲 ,交完后显示超出内存限制,我才去看数据范围:,怎么多边,肯定要超。然后就一直卡住了。
题解是:
先把花费的计算公式化简。
令 ,那么;
所以只要把所有的 从小到大排序,然后求出任意相邻两个之间的差值的绝对值,累加求和即可。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+5; ll a[N]; int main() { int n,x,y; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); a[i]=1LL*x*x*y-1LL*2*x*y*y+1LL*y*y*y; } sort(a+1,a+1+n); ll ans=0; for(int i=1;i<n;i++) ans+=abs(a[i]-a[i+1]); printf("%lld\n",ans); return 0; }
C.装备合成:
假设以第一种方式生成的装备数为 ,以第二种方式生成的装备数为 。
解法1:线性规划
一开始没有往这边想,看题解的时候看到有人这样写,才想起来高中还学过这个东西。
先写约束条件:
目标函数为:
问题的最优解在交点处取得。
可能的交点有直线与坐标轴的交点,两条直线的交点。但要保证点的坐标为整数。
与坐标轴的交点,直接向下取整即可。
注意的是,如果两条直线的交点不为整数,需要枚举其周围的 个点来求最大。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll x,y; bool check(ll a,ll b) { if(2*a+4*b<=x&&3*a+b<=y) return true; else return false; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%lld%lld",&x,&y); ll ax=min(x/2,y/3),ay=0; ll by=min(x/4,y),bx=0; ll cx=(4*y-x)/10,cy=(3*x-2*y)/10;//交点左下方的点 ll ans=max(ax,by); if(cx>=0&&cy>=0) { ans=max(ans,cx+cy); cx++; if(check(cx,cy)) ans=max(cx+cy,ans); cy++; if(check(cx,cy)) ans=max(cx+cy,ans); cx--; if(check(cx,cy)) ans=max(cx+cy,ans); } printf("%lld\n",ans); } return 0; }
解法2:三分
首先,暴力的想法,枚举 ,然后求出 ,找到最大值,但是会超时。枚举的过程中发现,最大值其实是有单调性的,所以用三分解决单峰函数最值问题。
证明单调性:
假设 个一类装备是最优的,减掉一个 类装备,最多只可能增加 个二类装备;增加一个 类装备,可能减少多个 类装备,因此在最优答案两边都是递减的。
写三分的时候,最后确定的是 个可能点即极值点的取值范围,无法确定具体的点。需要枚举求最大。
代码:
#include <bits/stdc++.h> using namespace std; int x,y; int solve(int a) { return a+max(0,min((x-2****-3*a)); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&x,&y); int l=0,r=min(x/2,y/3),ans=0; while(l+2<r) { int mid1=(l+r)>>1; int mid2=(mid1+r)>>1; if(solve(mid1)>solve(mid2)) r=mid2-1; else l=mid1+1; } for(int i=l;i<=r;i++) ans=max(ans,solve(i)); printf("%d\n",ans); } return 0; }
D.取石子游戏:
找必胜态和必输态,推出转移关系。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=100; vector<ll>num; int sg[N]; void init() { sg[0]=0; num.push_back(1); ll n=1; int cnt=1; while(n<=1e18) {//cout<<"n="<<n<<endl; if(cnt&1) { n=2*n+1; sg[++cnt]=1; } else { n=n*2; sg[++cnt]=0; } num.push_back(n); }//cout<<"cnt="<<cnt<<endl; } int main() { int t; ll n; init(); scanf("%d",&t); while(t--) { scanf("%lld",&n); int tt=lower_bound(num.begin(),num.end(),n)-num.begin();//cout<<"tt="<<tt+1<<endl; if(sg[tt+1]==1) printf("XiaoHuiHui\n"); else printf("XiaoQiao\n"); } return 0; }
E,F都涉及dp,还不会。
题解