收录了最近本人完成的一部分codeforces习题,不定期更新
codeforces 1132E Knapsack
注意到如果只使用某一种物品,那么这八种物品可以达到的最小相同重量为\(840\)
故答案一定可以被写成\(840k+x(k,x\in 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\n",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+x\equiv 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\n");fflush(stdout);
int cnt=get_num();
printf("next 0 1\n");fflush(stdout);
cnt=get_num();
if (cnt==2) break;
}
while (1)
{
printf("next 0 1 2 3 4 5 6 7 8 9\n");fflush(stdout);
int cnt=get_num();
if (cnt==1) break;
}
printf("done\n");fflush(stdout);
return 0;
}
原文地址:https://www.cnblogs.com/zhou2003/p/10739708.html