CSP-S加赛0905
下发文件和题解
A. ZZH的游戏
内存限制:512 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
输入格式
输出格式
样例
数据范围与提示
贪心,每次找到一个最优的方案(移左还是移右),把它所有将要到达的点放入优先队列中,直至两边都到1为止.
为了防止重复走某个点,开一个vis记录一下,清空不能用memset,会TLE.
点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 1000001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ll T,n,s,t,ans;
vector<ll> g1[maxn],g2[maxn];
priority_queue<ll,vector<ll>,greater<ll> > q1,q2;
ll vis1[maxn],vis2[maxn];
int main()
{
T=read();
while(T--)
{
while(!q1.empty()) q1.pop();while(!q2.empty()) q2.pop();n=read();
for(rll i=1;i<=n;i++) g1[i].clear(),g2[i].clear(),vis1[i]=vis2[i]=0;
for(rll i=1,a,b;i<n;i++) a=read(),b=read(),g1[a].push_back(b),g1[b].push_back(a);
for(rll i=1,a,b;i<n;i++) a=read(),b=read(),g2[a].push_back(b),g2[b].push_back(a);
s=read();t=read(); if(s==1&&t==1) { puts("2"); continue; } ans=s+t;q1.push(s);q2.push(t);
while(s!=1||t!=1)
{
if(q2.empty()||((!q1.empty())&&q1.top()+t<q2.top()+s))//移左比移右更优
{
rll x=q1.top();q1.pop();vis1[x]=1;
ans=max(ans,x+t);s=min(s,x);
for(rll i=0;i<g1[x].size();i++) if(!vis1[g1[x][i]]) q1.push(g1[x][i]);
}
else//移右比移左更优
{
rll x=q2.top();q2.pop();vis2[x]=1;
ans=max(ans,s+x);t=min(t,x);
for(rll i=0;i<g2[x].size();i++) if(!vis2[g2[x][i]]) q2.push(g2[x][i]);
}
}
write(ans);putn;
}
return 0;
}
B. ZZH与背包
内存限制:1024 MiB
时间限制:4000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
输入格式
输出格式
样例
数据范围与提示
折半搜索这个方法非常巧妙.
利用容斥,大小为l至r的方案数即是大小最大为r的方案数减去大小最大为l-1的方案数.
考虑到n的大小只有40,那么可以把这个40分成两个20. 先排一遍序,于是左半部分是小的数,右半部分是大的数. 把前面一半的所有组合情况搜索出来,后面一半的所有情况也搜索出来,sort一下以保证它的单调性.
在累加答案的时候,用一个双指针. 将右半部分的指针指向第一个小于等于要求的数,枚举左边的所有情况,每次找到左半部分当前数与右半部分的数的和小于等于要求值的最大的右半部分的数. 因为两半的所有情况是单调的,所以右半部分比当前找到的数小的数和左半部分的数的和一定比现在的数小,一定合法. 所以每次加上一个右半部分当前数的位置即可.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 5000001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ll n,q,l,r,mid;
ll v[maxn],tot;
ll a[maxn],lena,b[maxn],lenb;
static inline void dfsl(rll x,rll num)
{
if(x>mid) { a[++lena]=num; return; }
dfsl(x+1,num);dfsl(x+1,num+v[x]);
}
static inline void dfsr(rll x,rll num)
{
if(x>n) { b[++lenb]=num; return; }
dfsr(x+1,num);dfsr(x+1,num+v[x]);
}
static inline ll getans(rll x)
{
rll t=upper_bound(b+1,b+lenb+1,x)-b-1,ans=0;
for(rll i=1;i<=lena;i++)
{
while(t&&a[i]+b[t]>x) t--;
if(!t) break;ans+=t;
}
return ans;
}
int main()
{
n=read();q=read();mid=(n>>1);
for(rll i=1;i<=n;i++) v[i]=read();
sort(v+1,v+n+1);
dfsl(1,0);dfsr(mid+1,0);
sort(a+1,a+lena+1);sort(b+1,b+lenb+1);
while(q--)
{
l=read();r=read();
write(getans(r)-((!l)?0:getans(l-1)));putn;
}
return 0;
}
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/articles/16661899.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!