CCPC2022威海补题
B
C
D
根据题意状压DP就好了。我这里的实现应该是比较简洁的,先按照输入的格式,再把下半部分往右移,这样每个点相邻点都可以用同样的方向数组计算。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=20,M=(1<<20);
const int dx[6]={0,1,1,0,-1,-1},dy[6]={1,1,0,-1,-1,0};
int st[N]={0,1,1,1,2,3},ed[N]={0,3,4,5,5,5},id[N][N],to[N][6];
struct node{
int x,y;
}pos[N];
int n,a[N],f[M],pw[N];
int cal(int x){
int s=0;
for(int i=1;i<=n;i++) if(x&pw[i]) s++;
return s;
}
void pre(){
for(int i=1;i<=5;i++)
for(int j=st[i];j<=ed[i];j++) id[i][j]=++n,pos[n]=(node){i,j};
for(int i=1;i<=5;i++){
for(int j=st[i];j<=ed[i];j++){
for(int k=0;k<6;k++){
int x=i+dx[k],y=j+dy[k];
if(x<0 || x>5 || y<st[x] || y>ed[x]) continue;
to[id[i][j]][k]=id[x][y];
}
}
}
for(int i=1;i<=n;i++) scanf("%d",&a[i]),pw[i]=(1<<(i-1));
for(int cnt=0;cnt<=n;cnt++){
for(int i=0;i<(1<<n);i++) if(cal(i)==cnt){
for(int j=1;j<=n;j++) if(i&pw[j]){
f[i]=max(f[i],f[i-pw[j]]);
for(int k=0;k<6;k++){
int u=to[j][k],v=to[j][(k+3)%6];
if(!u || !v) continue;
if( i&pw[u] && !(i&pw[v]) ) f[i]=max(f[i],f[i-pw[u]+pw[v]-pw[j]]+a[j]);
}
}
}
}
}
int main()
{
pre();
int q; cin>>q;
while(q--){
int s=0;
for(int i=1;i<=n;i++){
char ch;
scanf(" %c",&ch);
if(ch=='#') s+=pw[i];
}
cout<<f[s]<<endl;
}
return 0;
}
F
就是根据题意,考虑走的路径,是一段段颜色相同的点,然后算一下答案就是每段和+下一个点取max,然后跑两遍floyed就行了。
这不比G简单多了。。。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=305,M=1e5+5;
const ll F=1e12;
int n,m,c[N],w[N];
struct edge{
int u,v;
}e[M];
ll d1[N][N],d2[N][N],ans[N][N];
void work(){
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
//d1
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) d1[i][j]=F;
for(int i=1;i<=n;i++) d1[i][i]=0;
for(int u,v,i=1;i<=m;i++){
scanf("%d%d",&u,&v);
e[i]=(edge){u,v};
if(c[u]==c[v]) d1[u][v]=w[u],d1[v][u]=w[v];
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j && c[i]==c[k] && c[j]==c[k])
d1[i][j]=min(d1[i][j],d1[i][k]+d1[k][j]);
}
//d2
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) d2[i][j]=F;
for(int i=1;i<=n;i++) d2[i][i]=0;
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v;
if(c[u]==c[v]) continue;
d2[u][v]=d2[v][u]=w[u]+w[v];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) if(j!=i && c[j]==c[i]){
//d2[i][j]=min(d2[i][j],d1[i][j]+w[j]);
for(int k=1;k<=n;k++) if(k!=i && k!=j && c[k]!=c[i])
d2[i][k]=min(d2[i][k],d1[i][j]+d2[j][k]);
}
}
/*for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) printf("%d ",d2[i][j]);
puts("");
}*/
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j)
d2[i][j]=min(d2[i][j],max(d2[i][k],d2[k][j]));
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans[i][j]=d2[i][j];
for(int k=1;k<=n;k++) if(c[k]==c[j]) ans[i][j]=min(ans[i][j],max(d2[i][k],d1[k][j]+w[j]));
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) printf("%lld ",ans[i][j]);
puts("");
}
}
int main()
{
int T; cin>>T; while(T--) work();
return 0;
}
G
I
J
K
看完题之后思路是很自然的:对于每个要求,就转化成对于l和r的限制。原本被题目解释干扰了,纠结了一下区间长度的限制觉得很复杂;后来发现只要l和r合法,区间长度就合法,所以对于1的限制直接取交,对于2的二选一的限制,直接按照l的限制排序,枚举l所在的区间,即可得到r的范围,再和一开始的交集取交即可。
这思路确实很容易也很好写,但写完疯狂wa2。。。还是有个小细节没注意到,,,有点破防
此处要和1取max,因为原本算出来的l可能小于0,原理其实和后面的和L取min是一样的,但1的限制太容易忽略(区间范围关系的计数题,应该把每个限制都写成区间的形式!!而不是只有一边的不等式),,,而且在上面其实考虑过限制1算出来<0的情况,也忘记考虑限制2了,只能说写题的时候脑子比较混乱
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
const int N=1e5+5,F=2e9+5;
int T,n,m,L,R;
struct node{
int l,r;
}p[N];
int mn[N];
bool cmp(node u,node v){
return u.l<v.l;
}
void work(int id){
cin>>n;
m=0;
L=F; R=1;
while(n--){
int t;
ll k,x;
scanf("%lld%lld%lld",&t,&k,&x);
ll s=k*(k-1)/2;
int l=(int)((x-s)/k),r=(int)((x+s-1)/k+1);
if(t==1) L=min(L,l),R=max(R,r);
else p[++m]=(node){l,r};
}
if(L<=0){
puts("0");
return;
}
if(L==F){
puts("-1");
return;
}
sort(p+1,p+m+1,cmp);
p[0]=(node){0,0};
p[m+1]=(node){F,F};
mn[m+1]=F;
for(int i=m;i;i--) mn[i]=min(p[i].r,mn[i+1]);
ll ans=0;
for(int i=0;i<=m;i++){
int a=max(1ll,p[i].l+1),b=min(L,p[i+1].l);
if(a>b || mn[i+1]<=R) continue;
if(b==F || mn[i+1]==F){
puts("-1");
return;
}
else ans+=1ll*(b-a+1)*(mn[i+1]-R);
}
cout<<ans<<endl;
}
signed main()
{
cin>>T;
for(int i=1;i<=T;i++) work(i);
return 0;
}
分类:
XCPC——比赛记录&题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?