codeforces选做
Posted zhou2003
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codeforces选做相关的知识,希望对你有一定的参考价值。
收录了最近本人完成的一部分codeforces习题,不定期更新
codeforces 1132E Knapsack
注意到如果只使用某一种物品,那么这八种物品可以达到的最小相同重量为(840)
故答案一定可以被写成(840k+x(k,xin N_+)),我们将(x)称为”余下的部分”
故而设(dp[i][j])为当前考虑了前(i)个物品,它们所占的余下的部分的重量为(j)时,最多可以组成多少个(840)
对于每个(i)预处理出枚举上界暴力转移即可
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x)&(-x)
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,a,b) for (int i=a;i>=b;i--)
#define maxd 1000000007
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
ll w,a[10],ans=0,dp[9][100100];
ll read()
{
ll x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int main()
{
w=read();
rep(i,1,8) a[i]=read();
ll maxp=8*840;
memset(dp,-1,sizeof(dp));
dp[0][0]=0;
rep(i,1,8)
{
rep(j,0,maxp)//余下的重量
{
if (dp[i-1][j]==-1) continue;
ll k=min(1ll*840/i,a[i]);
rep(p,0,k)//当前有多少作为余下的部分
{
dp[i][j+p*i]=max(dp[i][j+p*i],dp[i-1][j]+(a[i]-p)/(840/i));
}
}
}
ll ans=0;
rep(i,0,min(w,maxp))
{
if (dp[8][i]==-1) continue;
ans=max(ans,i+min((w-i)/840,dp[8][i])*840);
}
printf("%lld",ans);
return 0;
}
codeforces1154G Minimum Possible LCM
根据(lcm(x,y)=frac{xy}{gcd(x,y)})进行计算
枚举约数(d),每次找到满足(d|x)的最小的两个(x),用它们更新答案即可
为什么这样做可行?我们假设满足(d|x?)的数从小到大一次为(a_1,a_2,cdots,a_k?)
不妨对(a_1,a_2,a_k(k>2))这三个数进行分析,并且我们保证(gcd(a_1,a_k)=d),否则我们可以在枚举更大的(d)的时候考虑到这一组
- 若(gcd(a_1,a_2)=d),那么一定有(frac{a_1a_2}{gcd(a_1,a_2)}<frac{a_1a_k}{gcd(a_1,a_k)})
- 若(gcd(a_1,a_2)>d?),则(frac{a_1a_2}{gcd(a_1,a_2)}<frac{a_1a_2}{d}<frac{a_1a_k}{d}?)
证毕
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x)&(-x)
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,a,b) for (int i=a;i>=b;i--)
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
int n,a[1001000],cnt[10010000];
vector<int> ans;
int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
ll gcd(ll x,ll y)
{
if (!y) return x;else return gcd(y,x%y);
}
int main()
{
n=read();ll maxd=0;
rep(i,1,n) {a[i]=read();cnt[a[i]]++;maxd=max(maxd,1ll*a[i]);}
ll lcm=(ll)1e18+7,val1,val2;
rep(i,1,maxd)
{
int j;ans.clear();
for (j=i;j<=maxd;j+=i)
{
if (!cnt[j]) continue;
int tmp=cnt[j];
while ((tmp) && (ans.size()<2))
{
ans.push_back(j);
tmp--;
}
if (ans.size()==2) break;
}
if (ans.size()!=2) continue;
ll now=1ll*ans[0]*ans[1]/gcd(ans[0],ans[1]);
if (now<lcm)
{
lcm=now;val1=ans[0];val2=ans[1];
}
}
ll pos1=0,pos2=0;
rep(i,1,n)
{
if ((!pos1) && (a[i]==val1)) pos1=i;
else if ((!pos2) && (a[i]==val2)) pos2=i;
}
if (pos1>pos2) swap(pos1,pos2);
printf("%lld %lld",pos1,pos2);
return 0;
}
codeforces 1120D Power Tree
如果不要输出方案的话那就可以大力(dp),记(dp[u][0/1])为控制以(u)为根的子树的最小代价,其中(0)表示不选(u)的祖先(1)表示选,考虑(u)的儿子是不需要选祖先或者某一个需要祖先来进行转移
然而似乎输出方案很难写。。。弃了弃了看题解
将控制一个点的操作转化到树的dfs序上,也就是控制了一段区间,注意到这个(dfs)序我们只需要保留叶子结点
为了转化区间操作,我们将这个(dfs)转化成差分序列,即一次对([l,r])的操作可以看做是在(l)加上一个数同时在(r+1)上减去一个数
考虑题目是要求最后能使得整个序列都变成(0),等价于让这个差分序列变成(0)
也就是说对于每个点我们都希望有一条能单独修改它的路径
将差分序列的每个位置看成是一个点,一次修改看成是一条边,跑kruskal即可
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x)&(-x)
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,a,b) for (int i=a;i>=b;i--)
#define maxd 1000000007
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
struct sqnode{
int to,nxt;
}sq[400400];
struct edgenode{
int u,v,w,id;
}edge[200200];
bool operator <(const edgenode &p,const edgenode &q)
{
return p.w<q.w;
}
int n,w[200200],all=0,head[200200],l[200200],r[200200],tot=0,tim=0,fa[200200];
bool vis[200200];
int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int find(int x)
{
if (fa[x]==x) return x;
fa[x]=find(fa[x]);
return fa[x];
}
void dfs(int u,int fu)
{
int i;
l[u]=maxd;r[u]=0;
for (i=head[u];i;i=sq[i].nxt)
{
int v=sq[i].to;
if (v==fu) continue;
dfs(v,u);vis[u]=1;
l[u]=min(l[u],l[v]);
r[u]=max(r[u],r[v]);
}
if ((!vis[u]) && (u!=1)) {l[u]=(++tim);r[u]=tim;}
edge[++tot]=(edgenode){l[u],r[u]+1,w[u],u};
}
void add(int u,int v)
{
all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all;
}
int main()
{
n=read();
rep(i,1,n) w[i]=read();
rep(i,1,n-1)
{
int u=read(),v=read();
add(u,v);add(v,u);
}
memset(vis,0,sizeof(vis));
dfs(1,0);
sort(edge+1,edge+1+n);
ll ans=0;
rep(i,1,tim+1) fa[i]=i;
memset(vis,0,sizeof(vis));
int l=1,r=1;
for (l=1;l<=n;l=r+1)
{
while ((r<n) && (edge[r+1].w==edge[l].w)) r++;
rep(j,l,r)
{
int x=edge[j].u,y=edge[j].v,
fx=find(x),fy=find(y);
if (fx!=fy) vis[edge[j].id]=1;
}
rep(j,l,r)
{
int x=edge[j].u,y=edge[j].v,
fx=find(x),fy=find(y);
if (fx!=fy) {fa[fx]=fy;ans+=edge[j].w;}
}
}
int cnt=0;
rep(i,1,n) if (vis[i]) cnt++;
printf("%lld %d
",ans,cnt);
rep(i,1,n) if (vis[i]) printf("%d ",i);
return 0;
}
codeforces1137D Cooperative Game
学不来告辞
利用floyd和pollard-rho中的判圈方式,我们让(0)号棋子一次走一步,(1)号棋子两次走一步,直到两者相遇
我们假设此时(1)号棋子走了(T+x)步,那么(0)号棋子走了(2(T+x))步
且应有(T+xequiv 0(mod C))
因此(0)和(1)号这两颗棋子再走(T)步即可到达终点
且剩下的(8)棵棋子需要走一条链的长度,也是(T)步
于是我们可以在(2x+3T)的步数内完成这一过程,由于(x<C),所以总步数小于(3(T+C))
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x)&(-x)
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,a,b) for (int i=a;i>=b;i--)
#define maxd 1000000007
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
char s[20];
int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int get_num()
{
int ans=read();
rep(i,1,ans) scanf("%s",s);
return ans;
}
int main()
{
while (1)
{
printf("next 0
");fflush(stdout);
int cnt=get_num();
printf("next 0 1
");fflush(stdout);
cnt=get_num();
if (cnt==2) break;
}
while (1)
{
printf("next 0 1 2 3 4 5 6 7 8 9
");fflush(stdout);
int cnt=get_num();
if (cnt==1) break;
}
printf("done
");fflush(stdout);
return 0;
}
以上是关于codeforces选做的主要内容,如果未能解决你的问题,请参考以下文章
[Codeforces Round #522 (Div. 2, based on Technocup 2019 Elimination Round 3)][C. Playing Piano](代码片段