20240503比赛总结
T1 [CF1279C]Stack of Presents
https://gxyzoj.com/d/hzoj/p/3686
数据出锅了,100->40
按题意模拟即可,可以发现,最优情况下,一定是将取出的数按后面的拿的顺序排序,O(1)取出,而在取之前未排序的,则需要花2k+1的时间排序并取出
代码:
#include<cstdio>
#define ll long long
using namespace std;
int T,n,m,a[100005],b[100005],vis[100005];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
vis[a[i]]=i;
}
for(int i=1;i<=m;i++)
{
scanf("%d",&b[i]);
b[i]=vis[b[i]];
}
ll ans=0;
int id=0;
for(int i=1;i<=m;i++)
{
if(b[i]<id) ans++;
else
{
ans=ans+1ll*2*(b[i]-i)+1;
id=b[i];
}
// printf("%d\n",ans);
}
printf("%lld\n",ans);
}
return 0;
}
T2 [luogu5522]棠梨煎雪
https://gxyzoj.com/d/hzoj/p/3667
树状数组+卡常
没事千万别写线段树!!!
可以发现,如果同一位上既有0,又有1,则这个区间必然无解,而如果所有的都是?,则这一位有两种情况,乘法原理求解即可
如何判断0与1的情况?
直接用60个树状数组,记录每一位0和1的情况,然后求和即可
代码:
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
int n,m,q;
string s[100010];
int lowbit(int x)
{
return x & (-x);
}
struct tree{
int a[100010];
void add(int x,int val)
{
while(x<=m)
{
a[x]+=val;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while(x)
{
res+=a[x];
x-=lowbit(x);
}
return res;
}
}tr[65];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>q;
for(int i=1;i<=m;i++)
{
cin>>s[i];
for(int j=0;j<n;j++)
{
int x=s[i][j]-'0';
if(s[i][j]!='?')
tr[j*2+x].add(i,1);
}
}
int ans=0;
while(q--)
{
int opt;
cin>>opt;
if(opt==0)
{
int l,r;
cin>>l>>r;
int sum=1;
for(int i=0;i<n;i++)
{
int x=tr[i*2].query(r)-tr[i*2].query(l-1);
int y=tr[i*2+1].query(r)-tr[i*2+1].query(l-1);
if(x!=0&&y!=0)
{
sum=0;
break;
}
if(x==0&&y==0) sum<<=1;
}
ans^=sum;
// cout<<sum<<"\n";
}
else
{
int x;
string st;
cin>>x>>st;
for(int i=0;i<n;i++)
{
int tmp=s[x][i]-'0';
if(s[x][i]!='?')
tr[i*2+tmp].add(x,-1);
tmp=st[i]-'0';
if(st[i]!='?')
tr[i*2+tmp].add(x,1);
}
s[x]=st;
}
}
cout<<ans;
return 0;
}
T3 [luogu1174]打砖块
https://gxyzoj.com/d/hzoj/p/3685
先考虑前50%的数据,设
对于满分,存在一种情况,就是程序认为打Y所花的子弹为0,所以在子弹数为0的时候会继续加上所有Y的权值
所以这里可以记
记
根据以上分析,显然如果要打Y,则前面必然剩下一发子弹,在打完后也必然剩一发子弹,所以转移为:
接下来考虑最后一发打在N上的情况,这里引入一种借子弹的思想
在第x列和第y列最后一个都打到N时,考虑先不打x列的最后一个N,而是将子弹借给第y列打那个N后的Y,再将剩余的那一发子弹还给x去打N,从而获得更多的分
此时就存在两种情况
- i给[1,i-1]借,方程:
- i给[i+1,n]借,方程:
答案显然为
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,k,a[205][205],b[205][205];
int dn[205][205],dy[205][205],fn[205][205],fy[205][205];
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
char c;
cin>>c;
if(c=='Y') b[i][j]=1;
}
}
for(int j=1;j<=m;j++)
{
int tot=0;
for(int i=n;i>0;i--)
{
if(b[i][j]) dy[j][tot]+=a[i][j];
else
{
tot++;
dn[j][tot]=dy[j][tot-1]+a[i][j];
dy[j][tot]=dn[j][tot];
}
}
}
for(int i=1;i<=m;i++)
{
for(int j=0;j<=k;j++)
{
for(int l=0;l<=min(j,n);l++)
{
fy[i][j]=max(fy[i][j],fy[i-1][j-l]+dy[i][l]);
if(l!=0) fn[i][j]=max(fn[i][j],fy[i-1][j-l]+dn[i][l]);
if(j!=l) fn[i][j]=max(fn[i][j],fn[i-1][j-l]+dy[i][l]);
}
}
}
printf("%d",fn[m][k]);
return 0;
}
T4 「NOIP2015」斗地主
https://gxyzoj.com/d/hzoj/p/1181
暴力dfs,按题意模拟即可
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
int T,n,a[25],sum[20],ans;
inline void dfs(int x)
{
// printf("%d %d\n",x,use);
//printf("\n");
if(x>=ans) return;
int cnt=0;
for(int i=3;i<=14;i++)//单顺子
{
if(sum[i]==0) cnt=0;
else
{
cnt++;
if(cnt>=5)
{
for(int j=i-cnt+1;j<=i;j++) sum[j]--;
dfs(x+1);
for(int j=i-cnt+1;j<=i;j++) sum[j]++;
}
}
}
cnt=0;
for(int i=3;i<=14;i++)//双顺子
{
if(sum[i]<2) cnt=0;
else
{
cnt++;
if(cnt>=3)
{
for(int j=i-cnt+1;j<=i;j++) sum[j]-=2;
dfs(x+1);
for(int j=i-cnt+1;j<=i;j++) sum[j]+=2;
}
}
}
cnt=0;
for(int i=3;i<=14;i++)//三顺子
{
if(sum[i]<3) cnt=0;
else
{
cnt++;
if(cnt>=2)
{
for(int j=i-cnt+1;j<=i;j++) sum[j]-=3;
dfs(x+1);
for(int j=i-cnt+1;j<=i;j++) sum[j]+=3;
}
}
}
for(int i=2;i<=14;i++)
{
if(sum[i]<3) continue;
sum[i]-=3;
dfs(x+1);//三张牌
for(int j=2;j<=15;j++)//三带一
{
if(!sum[j]||i==j) continue;
sum[j]--;
dfs(x+1);
sum[j]++;
}
for(int j=2;j<=14;j++)//三带二
{
if(sum[j]<2||i==j) continue;
sum[j]-=2;
dfs(x+1);
sum[j]+=2;
}
sum[i]+=3;
if(sum[i]<4) continue;
sum[i]-=4;
dfs(x+1);//炸弹
for(int j=2;j<=15;j++)//四带二 +单牌
{
if(!sum[j]||i==j) continue;
sum[j]--;
for(int k=j+1;k<=15;k++)
{
if(!sum[k]||k==i||k==j) continue;
sum[k]--;
dfs(x+1);
sum[k]++;
}
sum[j]++;
}
for(int j=2;j<=14;j++)//四带二 +对牌
{
if(sum[j]<=1||i==j) continue;
sum[j]-=2;
for(int k=j+1;k<=14;k++)
{
if(sum[k]<2||k==i||k==j) continue;
sum[k]-=2;
dfs(x+1);
sum[k]+=2;
}
sum[j]+=2;
}
sum[i]+=4;
}
int tmp=0;
for(int i=1;i<=15;i++)
{
if(sum[i])tmp++;
}
ans=min(ans,x+tmp);
}
int main()
{
scanf("%d%d",&T,&n);
while(T--)
{
ans=n;
for(int i=1;i<=n;i++)
{
int b;
scanf("%d%d",&a[i],&b);
if(a[i]==0) sum[15]++;
else if(a[i]==1) sum[14]++;
else sum[a[i]]++;
}
// for(int i=1;i<=15;i++) printf("%d ",sum[i]);
// printf("\n");
dfs(0);
printf("%d\n",ans);
for(int i=2;i<=15;i++) sum[i]=0;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律