ICPC焦作站(EF)+思维+树上dp
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ICPC焦作站(EF)+思维+树上dp相关的知识,希望对你有一定的参考价值。
这场比赛依旧是三道题,E其实比我们出的D难一点,但确实在能力范围之内,出了就保底铜牌了,出的快的话说不定有银。策略很重要
E. Resistors in Parallel
大数+打表找规律。
最后得出公式:R=素数乘积/该素数的因子之和
由于范围达到了10的100次幂,有一次感受到python的便捷,但用的太少,不如c++顺手。
1.素数筛得出素数。2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47……
2.重点在于素数因子之和的处理。(分子各个质因子+1)的乘积。
# -*- coding: utf-8 -*-
prime=[]
def is_prime(n):
i=2
vis=[0 for i in range(n+5)]
while i*i<=n:
if vis[i]==0:
for j in range(i*2,n,i):
vis[j]=1
i+=1
for i in range(n+5):
if i==0 or i==1 : continue
if vis[i]==0:
prime.append(i)
def gcd(a,b):
return a if b==0 else gcd(b,a%b)
is_prime(100000)
for T in range(int(input())):
n=int(input())
sum1=1
sum2=1
i=0
while 1:
if sum1*prime[i]>n:
break
sum1*=prime[i]
sum2*=(prime[i]+1)
i+=1
g=gcd(sum1,sum2)
#print(sum1,sum2,sum2)
sum1//=g
sum2//=g
print(f"sum1/sum2")
E2. Divisible Numbers (hard version)
思路:
k1和k2是a、b乘积数的因子,因此得出公式:x*y=k*a*b=kk*k1*k2
分解a和b的质因子,再去深搜k1、k2对于各个质因子的所取个数
最后比较x和y的值小于等于c和d,即为找到满足要求的数。
#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
#define down 0.996
using namespace std;
const double eps=1e-8;
const double inf=1e18;
const int mod=998244353;
const int P=131;
const int N=7e5+5;
int a,b,c,d,ansx,ansy,flag;
map<int,int>mp;
vector<pair<int,int>>e;
int qpow(int x,int y)
int res=1;
while(y)
if(y&1) res*=x;x*=x;y>>=1;
return res;
void demcopse(int x)
for(int i=2;i*i<=x;i++)
if(x%i==0)
while(x%i==0) mp[i]++,x/=i;
if(x>1) mp[x]++;
void dfs(int num,int k1,int k2)
if(flag) return;
if(num==e.size())
int sx=(a/k1+1)*k1;
int sy=(b/k2+1)*k2;
if(sx<=c&&sy<=d)
flag=1,ansx=sx,ansy=sy;
return;
int x=e[num].first,y=e[num].second,pw=0,tmp=1;
pw=qpow(x,y);
for(int i=0;i<=y;i++)
dfs(num+1,k1*tmp,k2*(pw/tmp));
tmp*=x;
void solve()
mp.clear();e.clear();
ansx=ansy=flag=0;
cin>>a>>b>>c>>d;
demcopse(a);demcopse(b);
for(auto x:mp) e.push_back(x);
dfs(0,1,1);
if(flag)
cout<<ansx<<" "<<ansy<<endl;
else
cout<<"-1 -1"<<endl;
signed main()
ios;
int T;cin>>T;
while(T--)
solve();
return 0;
D. Paths on the Tree
题意:找到k条简单路径,每个点都有一个权值p[i]
,c[i]
为经过该点的次数,在满足一个分支节点的孩子|c[i]-c[j]|<=1
的情况下,要求各个点 的c[i]*p[i]
权值最大。
思路:
1.在满足题目限制条件的情况下,可看出对于一个结点的孩子来说,会有p(k%sz)个结点被多经过一次,因此我们需要找到权值较大的节点路径进行分配。
2.设计dp状态:f[u][0]
表示以u为根节点,没有被分配额外一次路径所获得的最大权值;
f[u][1]
表示以u为根节点,被分配额外一次路径所获得的最大权值.
3.对每一层的孩子节点可进行降序排列存到vector数组中。
#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
#define down 0.996
using namespace std;
const double eps=1e-8;
const double inf=1e18;
const int mod=998244353;
const int P=131;
const int N=2e6+5;
int n,k,p[N],dp[N][2];
vector<int>e[N];
void dfs(int u,int k)
dp[u][0]=p[u]*k;dp[u][1]=(k+1)*p[u];
vector<int>son;
for(int v:e[u]) son.push_back(v);
if(!son.size()) return;
int x=son.size();
int k1=k/x,k2=k%x;
vector<pair<int,int>>tp;
for(int v:son) dfs(v,k1);
for(int v:son) tp.push_back(dp[v][1]-dp[v][0],v);
sort(tp.begin(),tp.end(),[&](pair<int,int> &p,pair<int,int> &q)
return p.first>q.first;
);
for(int i=0;i<tp.size();i++)
int v=tp[i].second;
if(i<k2) dp[u][0]+=dp[v][1];
else dp[u][0]+=dp[v][0];
if(i<=k2) dp[u][1]+=dp[v][1];
else dp[u][1]+=dp[v][0];
void solve()
cin>>n>>k;
for(int i=0;i<=n;i++) e[i].clear();
for(int i=2;i<=n;i++)
int x;cin>>x;e[x].push_back(i);
for(int i=1;i<=n;i++) cin>>p[i];
dfs(1,k);
cout<<dp[1][0]<<endl;
signed main()
ios;
int T;cin>>T;
while(T--)
solve();
return 0;
D. Problem with Random Tests
略有取巧的做法,使用了bitset进行位运算,猜测前50位必会随机产生一个0
#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
#define down 0.996
using namespace std;
const double eps=1e-8;
const double inf=1e18;
const int mod=998244353;
const int P=131;
const int N=1e6+5;
int n;
string s;
void solve()
cin>>n>>s;
int g=0;
while(g<n&&s[g]!='1') g++;
if(g>=n)
cout<<0<<endl;return;
s=s.substr(g,n);
bitset<N>b1(s),b2(s);
string ans=b1.to_string();
for(int i=1;i<=50;i++)
ans=max(ans,(b1|(b2>>i)).to_string());
g=0;
while(g<ans.length()&&ans[g]!='1') g++;
cout<<ans.substr(g)<<endl;
signed main()
ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
F. Honeycomb
思路:这题输出的时候好像不能用ios,不然会wa 1.
1.使用bfs从起点搜索到终点,到达终点后判断退出,输出最小值。
2.对于走过的点可使用特殊字符进行标记,这样就不会走回头路了。找对6个方向记录到数组中即可。
#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
#define down 0.996
using namespace std;
const double eps=1e-8;
const double inf=1e18;
const int mod=998244353;
const int P=131;
const int N=1e6+5;
int r,c,sx,sy,tx,ty,row,col;
char mp[4005][6005];
int len[4005];
int dx[6]=-2,2,-2,2,-4,4;
int dy[6]=-6,-6,6,6,0,0;
queue<pair<pair<int,int>,int>>q;
bool check(int x,int xx,int y,int yy)
int kx=(x+xx)/2,ky=(y+yy)/2;
if(xx>=1&&xx<=row&&yy>=1&&yy<=len[xx]&&mp[xx][yy]!='@'&&mp[kx][ky]!='-'&&mp[kx][ky]!='/'&&mp[kx][ky]!='\\\\')
return 1;
return 0;
void solve()
while(!q.empty()) q.pop();
cin>>r>>c;
row=r*4+3,col=c*6+3;
for(int i=1;i<=row;i++)
len[i]=0;
for(int j=0;j<=col;j++) mp[i][j]=' ';
2018ACM-ICPC焦作站E题Resistors in Parallel
ACM-ICPC 2018 焦作赛区网络预赛 B. Mathematical Curse << DP
2018ICPC 焦作 B - Ultraman vs. Aodzilla and Bodzilla(贪心,思维)
2018ICPC 焦作 B - Ultraman vs. Aodzilla and Bodzilla(贪心,思维)