A:
题目: A. Divide it!
思路:
很明显变成 4/5n, 2/3n后又能被2整除,所以我们直接暴力就可以了。
AC_Code
long long getans(long long x) {
long long ans = 0;
while( x!=0 && x%5 == 0) {
ans += 3;
x /= 5;
}
while( x!=0 && x%3 == 0) {
ans += 2;
x /= 3;
}
while( x!=0 && x%2 == 0) {
ans += 1;
x /= 2;
}
return x == 1? ans: -1;
}
int main() {
int q;
cin>>q;
while(q--) {
long long n;
cin>>n;
cout<< getans(n)<<endl;
}
return 0;
}
B:
题目: B. Merge it!
思路:
读入的时候每个数都 %3, 统计 0,1,2的个数,然后 1和 2先优先匹配,会只剩下 1或者2,最后考虑剩下的 有没有 超过 3个,每3个又能构成一个.
AC_Code
int a[110];
int main() {
int t;
cin>>t;
while(t--) {
int n;
cin>>n;
int sum1=0,sum2=0;
for(int i = 0;i<n;i++) {
cin>>a[i];
a[i] %= 3;
if(a[i] == 1) sum1++;
else if(a[i] == 2)sum2++;
}
int ans = n - sum1 - sum2;
int d = min(sum1,sum2);
ans += d;
sum1 -= d;
sum2 -=d;
cout<< (ans + sum1/3+sum2/3) <<endl;
}
return 0;
}
C:
题目: C. Lose it!
思路:
先遍历一遍记录所有数的位置,然后暴力就可以了.
AC_Code
const int maxn = 5e5+7;
int a;
int sum[110];
std::vector<int> v[10];
int main() {
int n,res=0;
cin>>n;
for (int i = 0; i < n; ++i){
cin>>a;
if( a == 4 ) v[0].push_back(i);
if( a == 8 ) v[1].push_back(i);
if( a == 15) v[2].push_back(i);
if( a == 16) v[3].push_back(i);
if( a == 23) v[4].push_back(i);
if( a == 42) v[5].push_back(i);
}
int flag = 0;
int j=-1,k= -1,l= -1,o= -1,p= -1;
for(int i=0;i<v[0].size();i++) {
flag = 0;
for( j = j+1; j< v[1].size();j++) {
if( v[1][j] <v[0][i]) continue;
for(k = k+1 ; k<v[2].size();k++) {
if( v[2][k] <v[1][j]) continue;
for(l = l+1; l<v[3].size(); l++) {
if( v[3][l] <v[2][k]) continue;
for(o = o+1;o<v[4].size();o++) {
if( v[4][o] <v[3][l]) continue;
for(p = p+1;p<v[5].size();p++) {
if( v[5][p] <v[4][o]) continue;
flag = 1;
break;
}
break;
}
break;
}
break;
}
break;
}
if( flag == 1) res++;
else break;
}
cout<< n-res*6 <<endl;
return 0;
}
D:
题目: D. Recover it!
思路:
不难发现,对于b中的最大数,如果这个数不为素数,那么它一定是a数组中的数(约数一定小于其本身),如果为素数,那么它一定是由前面一个素数得到的(不难看出 Pa = b中, a一定小于 b)
有了上述结论,我们只要每次查询b数组中的最大值即可,这样的得到的解一定是合理的.
O(sqrt(n))的方式找数n的最大约数会T,所以我们可以通过素数筛同时记录该数的最小质因子来求得最大约数( n = 最大约数 * 最小值因子).
AC_Code
const int maxn = 2e5+7;
const int maxs = 2750131;
int n;
int b[maxn<<1];
int q[maxs+7];
int vis[maxs];
int yue[maxs];
std::vector<int> v;
void init() {
int now = 1;
for(long long i = 2;i<=maxs;i++) {
if(vis[i] != 0) continue;
vis[i] = now++;
for(long long j = i*i; j<=maxs;j+=i) {
if(vis[j] != 0) continue;
yue[j] = i;
vis[j] = -1;
}
}
return ;
}
int main() {
init();
scanf("%d",&n);
for(int i = 0;i<2*n;i++) {
scanf("%d",&b[i]);
q[b[i]]++;
}
sort(b,b+2*n);
for(int i=2*n-1;i>=0;i--) {
if(q[b[i]] == 0) continue;
q[b[i]]--;
if(vis[b[i]] == -1) {
v.push_back(b[i]);
q[ b[i]/yue[b[i]] ]--;
}
else {
// cout<<b[i]<<' '<<vis[b[i]]<<endl;
v.push_back(vis[b[i]]);
q[vis[b[i]]] --;
}
}
//cout<<v.size()<<endl;
for(int i = 0;i<v.size();i++) {
cout<<v[i];
if( i != v.size()-1) cout<<' ';
else cout<<endl;
}
return 0;
}
E:
题目: E. Cover it!
思路:
因为只要不超过 n/2都可以,所以我们不妨每次都选n/2,那么我们如果选择了一个点,那么与其相连的点肯定是不用选择了的,以此类推,如果最后我们选的点数超过了 n/2,那么我们只要认为 未选择点的才是我们选择的点就可以了(反过来肯定是合理的).
AC_Code
const int maxn = 2e5+7;
int vis[maxn];
int main() {
int t;
cin>>t;
while(t--) {
int ans = 0;
int n,m;
cin>>n>>m;
while(m --) {
int a,b;
cin>>a>>b;
if(vis[a] == 0 && vis[b] == 0) {
ans ++;
vis[a] = 1;
vis[b] = 2;
}
else if(vis[a] == 2 && vis[b] == 0) {
ans++;
vis[b]=1;
}
else if(vis[b] == 2 && vis[a] == 0) {
ans++;
vis[a]=1;
}
else if(vis[a] == 1 && vis[b] == 0) vis[b] = 2;
else if(vis[b] == 1 && vis[a] == 0) vis[a] = 2;
}
for(int i = 1;i<=n;i++) {
if( vis[i] == 0) {
ans++;
vis[i] = 1;
}
}
int res =1;
if( ans > n/2) {
res = 2;
ans = n-ans;
}
cout<< ans <<endl;
for(int i = 1;i<=n;i++) {
if(vis[i] != res) {
vis[i] = 0;
continue;
}
cout<<i;
ans--;
if(ans != 0) cout<<' ';
else cout<<endl;
vis[i] = 0;
}
}
return 0;
}
F:
题目: F. Destroy it!
前言: 这道题我赛后补的非常绝望!!!明明很容易想到思路但是不停出BUG.而且这道题给我杀戮尖塔既视感啊,钢笔尖天下第一!.
思路:
对于每回合我们只要 1费的伤害前3的牌,2费伤害最好的牌,3费伤害最高的牌即可,而且 出牌组合很少,可以直接枚举出来.
dp[i][k] 表示 第i回合打了 k张牌的最大伤害,我这里使用的滚动数组(不用也可以).
k每次超过 10 出牌组合中的伤害最好的牌伤害要翻倍. 因为 k我们只需要知道他是否会超过 10 所以我们 k < 10,否则会T掉.
AC_Code
// 不知道为什么 DP 和 MAX_HURT数组如果不初始化INF而是 0 的话就会WA掉,希望有个巨佬能看了代码后告诉我
int n;
int k;
vector<long long> v[5];
long long max_hurt[5][5];
long long dp[2][15];
int vis[15];
int now = 1;
void gethurt() {
for(int i =0;i<5;i++) for(int j = 0;j<3;j++) max_hurt[i][j] = -1; //初始化
max_hurt[0][0] = max_hurt[0][1] = 0;
for(int i =1;i<=3;i++) sort(v[i].begin(), v[i].end(),greater<int>() );
int len1 =v[1].size(),len2=v[2].size(),len3 = v[3].size();
if(len1 >= 3) {
max_hurt[3][0]= v[1][1]+v[1][2]+v[1][0];
max_hurt[3][1]= v[1][0]*2+v[1][1]+v[1][2];
}
if(len2 != 0) {
max_hurt[1][0] = max(max_hurt[1][0],v[2][0]);
max_hurt[1][1] = max(max_hurt[1][1],v[2][0]*2);
if(len1 != 0) {
max_hurt[2][0] = max(max_hurt[2][0],v[1][0]+v[2][0]);
max_hurt[2][1] = max(max_hurt[2][1],max(v[1][0],v[2][0])*2+min(v[1][0],v[2][0]));
}
}
if(len3 != 0) {
max_hurt[1][0] = max(max_hurt[1][0],v[3][0]);
max_hurt[1][1] = max(max_hurt[1][1],v[3][0]*2);
}
if(len1 >=2) {
max_hurt[2][0] = max(max_hurt[2][0],v[1][1]+v[1][0]);
max_hurt[2][1] = max(max_hurt[2][1],v[1][0]*2+v[1][1]);
}
if(len1 >=1) {
max_hurt[1][0] = max(max_hurt[1][0],v[1][0]);
max_hurt[1][1] = max(max_hurt[1][1],v[1][0]*2);
}
}
int main() {
vis[0] = 1;
scanf("%d",&n);
for(int i = 0;i<n;i++) {
int k;
scanf("%d",&k);
for(int p=0;p<k;p++) {
long long f,h;
scanf("%lld%lld",&f,&h);
v[f].push_back(h);
}
gethurt();
for(int l = 0; l<=9;l++) {
//cout<<l <<' '<<vis[l]<<endl;
if( vis[l] != 1) continue;
//cout<<l<<endl;
for(int m = 0;m<=3;m++) {
int nex = (l+m)%10;
int d = ((l+m)>=10? 1:0);
dp[now][nex] = max(dp[now][nex],dp[(now^1)][l]+max_hurt[m][d]);
vis[nex] = (vis[nex] == 1? 1:2);
}
}
now^=1;
for(int i = 0;i<=9;i++) if(vis[i] == 2) vis[i]=1;
memset(dp[now],0,sizeof(dp[now]));
for(int i = 1;i<=3;i++) v[i].clear();
/*for(int i =0;i<=up;i++) {
cout<< i<<' '<<dp[now^1][i]<<endl;
}*/
}
long long ans = 0;
for(int i = 0;i<=9;i++) {
ans = max(ans,dp[now^1][i]);
}
printf("%lld\n",ans);
return 0;
}