目录
A Golden Spirit
思路:
两岸各n个老人,都想去对岸并且休息x分钟。你每次可以带一个老人过桥需要t分钟。问需要最少需要多长时间完成并且接老人回来。
分析:每次带一个老人,假设从左边开始,第一个休息的老人在右边,你最终肯定在左边。接送老人共需要2(往返)*2*n*x分钟,问题就在于是首先接左边的老人还是右边的老人。假设接左边的。你需要等候额外的 【x-2*n*t+2*t<0?0:x-2*n*t+2*t;】(2*n*t-2*t是指送完老人左岸老人休息最长的时间)。如果先接送右边的。你需要等候【x-2*n*t<0?0:x-2*n*t】(老人休息2*n*t-t)。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<map>
#include<cmath>
#include<vector>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn = 1e6+50;
ll mod = 1e9+7;
int main(){
ll t,x,n,T;
cin >> T;
while(T--){
cin >> n >> x >> t;
ll sum1 = x-2*n*t+2*t<0?0:x-2*n*t+2*t;
ll sum2 = x-2*n*t<0?0:x-2*n*t;
ll maxs = min(sum1+4*n*t,sum2+t+4*n*t);
cout<<maxs<<endl;
}
return 0;
}
D ABC Conjecture
思路:
分析可以得到,根据唯一分解定理,如果一个数的拆分素数,指数都为1,那么肯定不可以满足上述条件,因为r(c)=c而不是大于c,更何况r(abc)>=r(c)=c
所以就看有没有素数的平方因子。如果c只能拆分为两个及以下,也就是拆分的应该大于等于1e6,这时根据开方(int)sqrt(c)*(int)sqrt(c)==c即可判断是否是相等的两个因子(有平方项)。
如果本身素数或者拆分的不等那么肯定不满足。接下来就欧拉筛出1e6进行判断即可。因为这时候只有有1e6以下的因子的情况。
注意:如果上来就判断的话,最后直接根据for里面的flag,会漏掉p*p*q,而p大于1e6,q小于1e6的情况。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<cstdio>
#include<cmath>
#include<stdlib.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll maxn = 1e6+50;
bool num[maxn];
ll pri[maxn];
void Elur(){
for(ll i = 2;i <= 1e6;i++){
if(!num[i]) pri[++pri[0]] = i;
for(ll j = 1;j <= pri[0]&&i*pri[j] <= 1e6;j++){
num[i*pri[j]] = true;
if(i%pri[j] == 0) break;
}
}
return ;
}
int main(){
cin.tie(0);cout.tie(0);
Elur();
ll T,c;
cin >> T;
while(T--){
cin >> c;
bool flag = false;
ll t = (ll)sqrt(c);
for(ll i = 1;pri[i] <= c&&i <= pri[0];i++){
if(c%(pri[i]*pri[i]) == 0){
flag = true;
break;
}
if(c%pri[i] == 0) c/=pri[i];
}
if(flag) cout<<"yes"<<endl;
else if(c > 1){
ll t = sqrt(c);
if(t*t == c) cout << "yes"<<endl;
else cout<<"no"<<endl;
}
else cout<<"no"<<endl;
}
return 0;
}
H Message Bomb
思路:
暴力解必定超时。需要想办法不在while(s--)里面有循环。容易想到差分求解。不过这个差分较为复杂。
设数组ans[u]代表第u个学生接收的message。cnt[v]表示目前为止第v个group接收的message。
对学生进去到出来进行差分。
t==1 u进入v。ans[u]-=cnt[v]。
t==2 u退出v。ans[u]+=cnt[v]。神奇般的加了回来。
t==3 u在v中发了条消息。ans[u]--,cnt[v]++。这样的目的,最终ans[u]+cnt[v]不应该接收这条消息,需要减一。
最终对于u加上所有最终所在的v的cnt[v]即可。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<map>
#include<cmath>
#include<vector>
#include<cstdio>
#include<set>
using namespace std;
typedef long long ll;
const int maxn = 2e5+50;
const int maxs = 1e5+50;
ll ans[maxn];//stu
ll cnt[maxs];//group
set<int>sec[maxn];
int main(){
int n,m,s;
cin >> n >> m >> s;
int t,u,v;
while(s--){//O(s)
scanf("%d%d%d",&t,&u,&v);
if(t == 1){//enter
ans[u]-=cnt[v];
sec[u].insert(v);
}
else if(t == 2){//leave
ans[u]+=cnt[v];
sec[u].erase(v);//O(logn)
}
else if(t == 3){//give a message
cnt[v]++;
ans[u]--;
}
}
for(int i = 1;i <= m;i++){
set<int>::iterator it = sec[i].begin();
for(;it != sec[i].end();it++){
ans[i] = ans[i]-cnt[*it];
}
printf("%d\n",ans[i]);
}
return 0;
}
L Clock Master
题目目的,对于给定的b。寻找n(不要求)个数a[i]…..a[n],使得a[i]+..a[n]<=b且lcm(a[i],…..,a[n])最大。
思路:
对于每一个数可以拆分为素数之积。而lcm又是取所有对应素因子的指数(可以看做为0)的最大值。这样如果有共同的因子就会被约掉一部分,浪费了一部分数。所以实质上就是求每个素数P={p^i}中选择一个。分组背包问题。
dp是记忆化算法,多组测试样例,预先算出最大的,这样直接while里面输出即可,否则会出现重复计算增加复杂度而导致超时。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<map>
#include<cmath>
#include<vector>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn = 3e4+50;
double dp[maxn];
int pri[maxn];
bool num[maxn];
double Log[maxn];
int N = 3e4;
void Elur(){
for(int i = 2;i <= 3e4;i++){
if(num[i]) pri[++pri[0]] = i;
for(int j = 1;j <= pri[0]&&i*pri[j] <= 3e4;j++){
num[i*pri[j]] = false;
if(i%pri[j] == 0) break;
}
}
return ;
}
void trans_Log(){
for(int i = 1;i <= 3e4;i++){
Log[i] = log(i);
}
for(int i = 1;i <= pri[0];i++){
for(int j = N;j >= pri[i];j--){
for(int k = pri[i];k <= j;k*=pri[i])
dp[j] = max(dp[j],dp[j-k]+Log[k]);
}
}
}
int main(){
memset(num,true,sizeof(num));
Elur();
trans_Log();
int n,t;
cin >> t;
while(t--){
scanf("%d",&n);
printf("%0.9lf\n",dp[n]);
}
return 0;
}