A.模拟即可,最多不会超过3logn次
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <cmath> #include <algorithm> using namespace std; int n,ans; long long x; int main() { scanf("%d",&n); while (n--) { scanf("%lld",&x); ans=0; while (x>1) { bool ff=0; if (x%2==0) x/=2,ff=1; else if (x%3==0) x/=3,x*=2,ff=1; else if (x%5==0) x/=5,x*=4,ff=1; ans++; if (!ff) break; } if (x==1) printf("%d\n",ans);else printf("-1\n"); } return 0; }
B.贪心,先把3的倍数全弄出来,然后考虑%3为1,2的配对,然后考虑各自配对
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <cmath> using namespace std; const int maxn=110; int T,n,x,ans,num1,num2; int main() { scanf("%d",&T); while (T--) { scanf("%d",&n); ans=0; num1=0; num2=0; for (int i=1;i<=n;i++) { scanf("%d",&x); x%=3; if (x==0) ans++; if (x==1) num1++; if (x==2) num2++; } int k=min(num1,num2); ans+=k; num1-=k; num2-=k; printf("%d\n",ans+num1/3+num2/3); } return 0; }
C.贪心,对于同一个字母,若在前面能构成合法序列的话一定比在后面优
#include <iostream> #include <cstdio> #include <cstdlib> using namespace std; const int maxn=500010; int n,a[maxn],ans,sum[50]; int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=n;i++) if (a[i]==4) sum[4]++; else if (a[i]==8 && sum[4]) sum[4]--,sum[8]++; else if (a[i]==15 && sum[8]) sum[8]--,sum[15]++; else if (a[i]==16 && sum[15]) sum[15]--,sum[16]++; else if (a[i]==23 && sum[16]) sum[16]--,sum[23]++; else if (a[i]==42 && sum[23]) sum[23]--,ans++; printf("%d\n",n-6*ans); return 0; }
D.排序,首先对于合数,从大往小找是否有最大因子,有的话就是原数列,对于剩下的质数从小往大找
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> using namespace std; const int maxn=400010; int n,a[maxn],prime[2*maxn],cnt,num[3000010],ans[maxn],topt; bool f[3000010]; bool cmp(int aa,int bb){return aa>bb;} int main() { memset(f,1,sizeof f); f[0]=f[1]=0; for (int i=2;i<=3000000;i++) { if (f[i]) prime[++cnt]=i; for (int j=1;j<=cnt && 1ll*i*prime[j]<=3000000;j++) { f[i*prime[j]]=0; if (i%prime[j]==0) break; } } scanf("%d",&n); n*=2; for (int i=1;i<=n;i++) scanf("%d",&a[i]),num[a[i]]++; sort(a+1,a+n+1,cmp); for (int i=1;i<=n;i++) if (!f[a[i]] && num[a[i]]) { int x; for (x=2;1ll*x*x<=a[i];x++) if (a[i]%x==0) break; if (num[a[i]/x]) ans[++topt]=a[i],num[a[i]]--,num[a[i]/x]--; } for (int i=n;i>=1;i--) if (f[a[i]] && num[a[i]]) { if (num[prime[a[i]]]) ans[++topt]=a[i],num[a[i]]--,num[prime[a[i]]]--; } for (int i=1;i<=topt;i++) printf("%d ",ans[i]); return 0; }
E.问题等价于对于图中的每条边,我们要使其两端的端点至少有一个被选中,这就变成了黑白染色问题,最后黑白两点谁少就输出谁
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> using namespace std; const int maxn=200010; int T,n,m,topt,st[maxn<<1],nt[maxn<<1],to[maxn<<1],col[maxn],sum1,sum2; bool f[maxn]; void add(int x,int y) {to[++topt]=y; nt[topt]=st[x]; st[x]=topt;} void init() { for (int i=1;i<=topt;i++) st[i]=0; topt=0; sum1=sum2=0; } void dfs(int x,int co) { f[x]=1; col[x]=co; int p=st[x]; if (co) sum1++;else sum2++; while (p) { if (!f[to[p]]) dfs(to[p],co^1); p=nt[p]; } } int main() { scanf("%d",&T); while (T--) { init(); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) f[i]=0,col[i]=0; for (int i=1;i<=m;i++) { int xx,yy; scanf("%d%d",&xx,&yy); add(xx,yy); add(yy,xx); } dfs(1,0); if (sum1<sum2) { printf("%d\n",sum1); for (int i=1;i<=n;i++) if (col[i]) printf("%d ",i); printf("\n"); } else { printf("%d\n",sum2); for (int i=1;i<=n;i++) if (!col[i]) printf("%d ",i); printf("\n"); } } return 0; }
F.dp,对于每轮将攻击力从大到小排序,处理两个数组,a[i][j],b[i][j]表示这一轮花费了i的费用,这一轮选了j个最大攻击力(a表示第一个选的攻击力翻倍,b正常),对于每轮,0/1背包搞一搞,对于全局,维护一个dp[i][j]表示当前打了i轮,已经打了j个人(模10)的最大值,用a.b转移一波就ok了
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <string> using namespace std; const int maxn=200010; int T,n,t; long long dp[2][12],k,ans,a[5][5],b[5][5]; struct da{int c;long long v;}q[maxn]; bool cmp(da aa,da bb) { if (aa.v==bb.v) return aa.c<bb.c; return aa.v>bb.v; } int main() { scanf("%d",&T); memset(dp[t],-1,sizeof dp[t]); dp[t][0]=0; while (T--) { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d%lld",&q[i].c,&q[i].v); memset(a,-1,sizeof a); memset(b,-1,sizeof b); a[0][0]=0; b[0][0]=0; t^=1; memset(dp[t],-1,sizeof dp[t]); sort(q+1,q+n+1,cmp); for (int i=1;i<=n;i++) for (int j=3-q[i].c;j>=0;j--) for (int k=0;k<3;k++) { if (a[k][j]!=-1) { if (j==0) a[k+1][j+q[i].c]=max(a[k+1][j+q[i].c],a[k][j]+2ll*q[i].v); else a[k+1][j+q[i].c]=max(a[k+1][j+q[i].c],a[k][j]+q[i].v); } if (b[k][j]!=-1) b[k+1][j+q[i].c]=max(b[k+1][j+q[i].c],b[k][j]+q[i].v); } for (int i=0;i<=9;i++) for (int j=0;j<=3;j++) for (int k=0;k<=3;k++) if (dp[t^1][i]!=-1) { if (i+j>=10 && a[j][k]!=-1) dp[t][(i+j)%10]=max(dp[t][(i+j)%10],dp[t^1][i]+a[j][k]); else if (b[j][k]!=-1) dp[t][(i+j)%10]=max(dp[t][(i+j)%10],dp[t^1][i]+b[j][k]); } } for (int i=0;i<10;i++) ans=max(ans,dp[t][i]); printf("%lld\n",ans); return 0; }