agc001 vp记录
AGC质量是真的高啊
- [AGC001A] BBQ Easy
史努克在参加一个BBQ派对, 他要准备N组食物, 他有2N的食材, 需要两两组成一个食物, 食物的价值是两食材中较小的那个。 问最大总价值是多少
签到题。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=400;
int n,sum[N],ans;
signed main(){
n=rd()*2;
for(int i=1;i<=n;i++)sum[i]=rd();
sort(sum+1,sum+1+n);
for(int i=1;i<=n;i+=2)ans+=sum[i];
printf("%d\n",ans);
return 0;
}
高桥くん有一个边长为N的三枚镜子构成的正三角形, 顶点为a, b, c。他有一个超级步枪,放在AB段的P点上,使得AP=X。并沿着平行于BC的方向发射一道光。
光以直线传播,以镜子的形式反射,但是有一个特殊的地方:它会被自己的轨迹反射,当光回到步枪的时候,光被吸收。
下面的图显示了当n=5,x=2时的光轨迹。
无论光线轨迹和n和x如何, 求出光线的总长度。
问题规模逐步缩小,于是可以考虑递归求解,手推一下规律发现每次对答案的贡献是 ,其中 x 和 y 是长边和短边的长度。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
int ans,n,m;
void dfs(int x,int y){
if(!y)return ans-=x,void(0);
ans+=2*(x-x%y);
dfs(y,x%y);
return ;
}
signed main(){
n=ans=rd(),n-=(m=rd());
dfs(n,m);
printf("%lld\n",ans);
return 0;
}
- [AGC001C] Shorten Diameter
给你一颗无向树,使定点U和V之间的距离是从U到V的简单路径上的边数。
你需要删除一些点,使树的直径小于等于K,当且仅当删除某点不会对树的联通性产生影响时才可以删除。问至少删除多少点才可以满足要求。
简单树形DP,随便推一下就行。这题为啥能评紫
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=2010;
int n,K,f[N][N],g[N][N],dep[N],siz[N],ans=INT_MAX;
int head[N],to[N*2],fro[N*2],tail;
inline void adlin(int x,int y){
to[++tail]=y,fro[tail]=head[x],head[x]=tail;
return ;
}
void dfs(int u,int fa){
siz[u]=1;
f[u][0]=0;
for(int k=head[u];k;k=fro[k]){
int x=to[k];
if(x==fa)continue;
dfs(x,u),siz[u]+=siz[x];
dep[u]=max(dep[u],dep[x]+1);
for(int i=0;i<=dep[u];i++)g[u][i]=INT_MAX;
for(int i=dep[u];i>=0;i--){
for(int j=0;j<=dep[x]&&i+j<=K;j++){
g[u][max(i,j)]=min(g[u][max(i,j)],f[u][i]+f[x][j]);
}
}
for(int i=0;i<=dep[u];i++)f[u][i]=g[u][i];
}
for(int i=dep[u];i>=1;i--)f[u][i]=f[u][i-1];
f[u][1]=min(f[u][1],siz[u]-1),f[u][0]=siz[u];
if(siz[u]==1)dep[u]=1;
for(int i=0;i<=dep[u];i++)ans=min(ans,n-siz[u]+f[u][i]);
// cout<<u<<":"<<dep[u]<<":";
// for(int i=0;i<=dep[u];i++)cout<<f[u][i]<<" ";
// cout<<"\n";
return ;
}
signed main(){
n=rd(),K=rd();
for(int i=1;i<n;i++){
int x=rd(),y=rd();
adlin(x,y),adlin(y,x);
}
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)f[i][j]=INT_MAX;
dfs(1,0);
printf("%lld\n",ans);
return 0;
}
- [AGC001D] Arrays and Palindrome
这题就不搬题面了。谢谢翻译的人我打死没看懂你翻译的是什么
简单的使得回文串移位的构造题,代码更清晰。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=100010;
int n,m,a[N],b[N],t;
signed main(){
n=rd(),m=rd();
for(int i=1;i<=m;i++){
a[i]=rd();
if(a[i]&1)b[++t]=i;
}
if(t>2){
printf("Impossible\n");
return 0;
}
if(t>=1)swap(a[1],a[b[1]]);
if(t>=2)swap(a[m],a[b[2]]);
for(int i=1;i<=m;i++)printf("%d ",a[i]);
printf("\n");
b[1]=a[1]+1;
for(int i=2;i<=m;i++)b[i]=(i==m)?a[i]-1:a[i];
if(m==1){
if(a[1]==1)printf("1\n1");
else printf("2\n%d %d\n",a[1]-1,1);
return 0;
}
if(a[m]==1)m--;
printf("%d\n",m);
for(int i=1;i<=m;i++)printf("%d ",b[i]);
return 0;
}
有 n 个数对 (; ),求出
答案对1e9+7取模
高妙组合题(然而被机房大佬说是典中典)。
这个式子不太能做,我们要将它拆分为之和 i 或 j 有关的部分。
n 1e5 不太能做,然而 a b 值域只有2000,于是考虑组合意义。
上式代表从走到,如果将线路平移到从到仍然成立。
现在之和i,j单独相关了。
于是我们将所有加1,左下向右上做一遍DP,统计每个处的答案。
减去自己到自己的部分,即。
最终答案除二。
实际也是有强推式子的做法,具体见luogu题解。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=5010,M=100000,K=2050,mod=1000000007;
int n,a[200010],b[200010],f[N][N];
int fps[M],inv[M],ans;
inline int pw(int x,int y){
int ansn=1;
while(y){
if(y&1)ansn=ansn*x%mod;
x=x*x%mod,y/=2;
}
return ansn;
}
inline int C(int x,int y){return fps[x]*inv[y]%mod*inv[x-y]%mod;}
signed main(){
fps[0]=inv[0]=1;
for(int i=1;i<M;i++)fps[i]=fps[i-1]*i%mod;
inv[M-1]=pw(fps[M-1],mod-2);
for(int i=M-2;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod;
n=rd();
for(int i=1;i<=n;i++)a[i]=rd(),b[i]=rd();
for(int i=1;i<=n;i++)f[-a[i]+K][-b[i]+K]++;
for(int i=0;i<=K*2;i++){
for(int j=0;j<=K*2;j++){
f[i+1][j]+=f[i][j],f[i+1][j]%=mod;
f[i][j+1]+=f[i][j],f[i][j+1]%=mod;
}
}
for(int i=1;i<=n;i++)ans+=f[a[i]+K][b[i]+K],ans%=mod;
for(int i=1;i<=n;i++)ans-=C(a[i]*2+b[i]*2,a[i]*2),ans=(ans%mod+mod)%mod;
printf("%lld\n",ans*inv[2]%mod);
return 0;
}
- [AGC001F] Wide Swap
给出一个元素集合为 的排列,当有 满足 且时,可以交换和
求:可能排列中字典序最小的排列
人类智慧题。
考虑第一个条件不太好做,然而第二个条件有非常优良的限制,于是人类智慧:令 ,能否交换相邻两个即为相邻数差是否大于等于 K 。
考虑冒泡排序,时间,不优,如何优化?
使用归并排序,先处理一个左边的后缀最小值,右边的数能比左边的先归并当且仅当右边的数加 K 小于等于左边数的后缀最小值。
关键还是要从题目条件入手。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=500010;
int n,K,sum[N],p[N],mi[N];
void merge(int l,int r){
if(l==r)return ;
int mid=(l+r)/2;
merge(l,mid),merge(mid+1,r);
for(int i=mid,x=INT_MAX;i>=l;i--)x=mi[i]=min(p[i],x);
int ll=l,rr=mid+1,t=l;
while(ll<=mid&&rr<=r){
if(p[ll]>p[rr]&&mi[ll]>=p[rr]+K)sum[t++]=p[rr++];
else sum[t++]=p[ll++];
}
while(ll<=mid)sum[t++]=p[ll++];
while(rr<=r)sum[t++]=p[rr++];
for(int i=l;i<=r;i++)p[i]=sum[i];
return ;
}
signed main(){
n=rd(),K=rd();
for(int i=1;i<=n;i++)p[rd()]=i;
merge(1,n);
for(int i=1;i<=n;i++)sum[p[i]]=i;
for(int i=1;i<=n;i++)printf("%d\n",sum[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】