2020CCPC威海站(部分)

目录

 

A Golden Spirit

思路:

代码:

D ABC Conjecture

思路:

代码:

H Message Bomb

思路:

代码:

L Clock Master

思路:

代码:


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;

}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值