G题:
队友写的,大概就是对w排序,然后背包的时候对后面还没背包到的物品贪心用免费的次数。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e4+10;
int n,m,k,dp[N],p[N];
struct demo{
int a, b;
}q[N];
bool cmp(demo a,demo b){
if(a.a==b.a)
return a.b>b.b;
return a.a<b.a;
}
priority_queue<int,vector<int>,greater<int> >w;
signed main(){
cin >> n >> m >> k;
for(int i=1;i<=n;i++){
cin >> q[i].a >> q[i].b;
}
sort(q+1,q+1+n,cmp);
int s=0;
for(int i=n;i>0;i--){
if(w.size()<k){
w.push(q[i].b);
s+=q[i].b;
}else if(w.size()>0&&q[i].b>w.top()){
s-=w.top();
w.pop();
s+=q[i].b;
w.push(q[i].b);
}
p[i]=s;
}
int ans=LONG_LONG_MIN;
for(int i=1;i<=n;i++){
for(int j=m;j>=q[i].a;j--){
dp[j]=max(dp[j],dp[j-q[i].a]+q[i].b);
}
ans=max(ans,dp[m]+p[i+1]);
}
cout << ans << endl;
}
C题:
问题转化成g^(p-1)-k*p=1,再转化成g=(1+k*p)^(p-1),然后就是找k,使得g<=m,发现没有单调性,但可以发现在一定范围(就是每几十个?)还是存在单调性的,也就是说如果这几十个数都大于m那么就是结束点,这个可以二分找。容易知道找到这个最大点后,前面可能有不满足的k,同样只需要判断几十个即可,遍历一遍。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll p,m;
bool check(ll k){
for(int i=0;i<=20;i++){
__int128 g=(1+(__int128)(i+k)*p)^(p-1);
if(g<=m)
return 1;
}
return 0;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
cin>>p>>m;
//g=(1+k*p)^(p-1)
ll l=0,r=1e18;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid))
l=mid+1;
else
r=mid-1;
}
ll ans=r+1;
for(__int128 i=r;i>=r-30;i--){
__int128 g=(1+(__int128)i*p)^(p-1);
if(g>m) ans--;
}
cout<<ans<<endl;
}
return 0;
}
F题
队友写的,可以发现每个位置的值只有不被最后覆盖即可,前面的操作可以任意排列,所以只需要让前面的操作连向最后一次操作一条边,表示先后顺序即可,拓扑排序。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 5;
const int mod = 1e9+7;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
#define fi first
#define se second
int n, m;
vector<int> ee[N];
vector<int> ne[N];
int in[N], ans[N];
void init(int n, int m){
for(int i = 1; i <= m; i++){
ee[i].clear();
}
for(int i = 1; i <= n; i++){
in[i] = 0;
ans[i] = 0;
ne[i].clear();
}
}
void solve(){
cin >> n >> m;
init(n, m);
for(int i = 1; i <= n; i++){
int p; cin >> p;
for(int j = 0; j < p; j++){
int x; cin >> x;
ee[x].push_back(i);
}
}
for(int i = 1; i <= m; i++){
if(ee[i].size() < 2) continue;
int sz = ee[i].size();
for(int j = 0; j < ee[i].size() - 1; j++){
ne[ee[i][j]].push_back(ee[i][sz - 1]);
in[ee[i][sz - 1]]++;
}
}
priority_queue<int> q;
for(int i = n; i >= 1; i--){
if(in[i] == 0) q.push(i);
}
int tp = 0;
while(!q.empty()){
int t = q.top();
q.pop();
ans[++tp] = t;
for(auto y : ne[t]){
in[y]--;
if(in[y] == 0){
q.push(y);
}
}
}
int f = 0;
for(int i = 1; i <= n; i++){
if(ans[i] != i) f = 1;
}
if(!f){
cout << "No" << endl;
return ;
}
cout << "Yes" << endl;
for(int i = 1; i <= n; i++){
cout << ans[i] <<" ";
}
cout << endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while(_--){
solve();
}
return 0;
}
M题:
原式子可以发现f【i】和g【i】其中一个肯定是a【i】里的最大值,而这最大值同样是max(f【i】,g【i】),所以min(f【i】,【g【i】】)可以看成f【i】+g【i】-max a【i】,然后就求sigma f【i】+sigma g【i】-n*max a【i】-sigma a【i】即可
tle的方法
容易发现f【i+1】>=f【i】,g【i】>=g【i+1】,有单调性,可以发现一定存在位置p,使得1到p min(f【i】,g【i】)取f【i】,p+1到n取g【i】,可以二分这个位置然后去判断f【i】和g【i】的大小就可以得出位置,然后原式变成f【1】+...f【p】+g【p+1】+...g【n】-sigma a【i】就是答案,这样是loglog的。对于修改f数组和g数组也可以利用二分去找增加v后应该修改的一些位置,因为f【i】和g【i】都是单调的,所以需要修改的区间也是连续的一段,最后区间修改即可,这样也是loglog的,最终这个方法的nloglog的,会tle。
nlog的方法
就用sigma f【i】+sigma g【i】-n*max a【i】-sigma a【i】这个式子,难度在怎么维护f数组和g数组。上面寻找位置都是通过二分再加上去线段树找值所以是loglog,因为f数组和g数组本身的单调的,所以我们考虑直接在线段树上去找位置。对于f数组,如果我们要找小于等于x的最远位置,我们令设一个fmin线段树来记录区间最小值,因为f数组单调递增,所以如果fmin【右儿子】<=x,那么我们就去右儿子找,否则去左儿子找,g数组同理。这样我们可以在log的时间找到需要修改的位置,然后直接区间修改即可。
代码:
#define LOCAL
#include<bits/stdc++.h>
using namespace std;
namespace ly
{
namespace IO
{
#ifndef LOCAL
#define SIZE (1<<20)
char in[SIZE],out[SIZE],*p1=in,*p2=in,*p3=out;
#define getchar() (p1==p2&&(p2=(p1=in)+fread(in,1,SIZE,stdin),p1==p2)?EOF:*p1++)
#define flush() (fwrite(p3=out,1,SIZE,stdout))
#define putchar(ch) (p3==out+SIZE&&flush(),*p3++=(ch))
class Flush{public:~Flush(){flush();}}_;
#endif
template<typename type>
inline void read(type &x)
{
x=0;bool flag(0);char ch=getchar();
while(!isdigit(ch)) flag^=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
flag?x=-x:0;
}
template<typename type>
inline void write(type x,bool flag=1)
{
x<0?x=-x,putchar('-'):0;static short Stack[50],top(0);
do Stack[++top]=x%10,x/=10;while(x);
while(top) putchar(Stack[top--]|48);
flag?putchar('\n'):putchar(' ');
}
#ifndef LOCAL
#undef SIZE
#undef getchar
#undef putchar
#undef flush
#endif
}
}using namespace ly::IO;
typedef long long ll;
#define int long long
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const int N=1e5+10;
const int mod=1e9+7;
#define fi first
#define se second
int n,a[N];
int fsum[N*4],gsum[N*4];
int maxx[N*4];
int lzf[N*4],lzg[N*4];
int ffmin[N*4],ggmin[N*4];
void pushupbuild(int p){
maxx[p]=max(maxx[p<<1],maxx[p<<1|1]);
}
void build(int p,int l,int r){
fsum[p]=gsum[p]=maxx[p]=lzf[p]=lzg[p]=ffmin[p]=ggmin[p]=0;
if(l==r){
maxx[p]=a[l];
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushupbuild(p);
}
void modify(int p,int l,int r,int x,int y){
if(l==r){
maxx[p]+=y;
return;
}
int mid=(l+r>>1);
if(x<=mid) modify(p<<1,l,mid,x,y);
else modify(p<<1|1,mid+1,r,x,y);
pushupbuild(p);
}
void pushupf(int p){
fsum[p]=fsum[p<<1]+fsum[p<<1|1];
ffmin[p]=min(ffmin[p<<1],ffmin[p<<1|1]);
}
void pushdownf(int p,int l,int r){
int mid=(l+r)>>1;
fsum[p<<1]=(mid-l+1)*lzf[p];
fsum[p<<1|1]=(r-mid)*lzf[p];
ffmin[p<<1]=lzf[p];
ffmin[p<<1|1]=lzf[p];
lzf[p<<1]=lzf[p];
lzf[p<<1|1]=lzf[p];
lzf[p]=0;
}
void modifyf(int p,int l,int r,int x,int y,int z){
if(x<=l&&y>=r){
fsum[p]=(r-l+1)*z;
lzf[p]=z;
ffmin[p]=z;
return;
}
if(lzf[p])
pushdownf(p,l,r);
int mid=(l+r)>>1;
if(x<=mid) modifyf(p<<1,l,mid,x,y,z);
if(y>mid) modifyf(p<<1|1,mid+1,r,x,y,z);
pushupf(p);
}
void pushupg(int p){
gsum[p]=gsum[p<<1]+gsum[p<<1|1];
ggmin[p]=min(ggmin[p<<1],ggmin[p<<1|1]);
}
void pushdowng(int p,int l,int r){
int mid=(l+r)>>1;
gsum[p<<1]=(mid-l+1)*lzg[p];
gsum[p<<1|1]=(r-mid)*lzg[p];
ggmin[p<<1]=lzg[p];
ggmin[p<<1|1]=lzg[p];
lzg[p<<1]=lzg[p];
lzg[p<<1|1]=lzg[p];
lzg[p]=0;
}
void modifyg(int p,int l,int r,int x,int y,int z){
if(x<=l&&y>=r){
gsum[p]=(r-l+1)*z;
lzg[p]=z;
ggmin[p]=z;
return;
}
if(lzg[p])
pushdowng(p,l,r);
int mid=(l+r)>>1;
if(x<=mid) modifyg(p<<1,l,mid,x,y,z);
if(y>mid) modifyg(p<<1|1,mid+1,r,x,y,z);
pushupg(p);
}
int querymax(int p,int l,int r,int x,int y){
if(x<=l&&y>=r){
return maxx[p];
}
int res=-1e18;
int mid=(l+r)>>1;
if(x<=mid) res=max(res,querymax(p<<1,l,mid,x,y));
if(y>mid) res=max(res,querymax(p<<1|1,mid+1,r,x,y));
return res;
}
int queryfsum(int p,int l,int r,int x,int y){
if(x<=l&&y>=r){
return fsum[p];
}
if(lzf[p])
pushdownf(p,l,r);
int res=0;
int mid=(l+r)>>1;
if(x<=mid) res+=queryfsum(p<<1,l,mid,x,y);
if(y>mid) res+=queryfsum(p<<1|1,mid+1,r,x,y);
pushupf(p);
return res;
}
int querygsum(int p,int l,int r,int x,int y){
if(x<=l&&y>=r){
return gsum[p];
}
if(lzg[p])
pushdowng(p,l,r);
int res=0;
int mid=(l+r)>>1;
if(x<=mid) res+=querygsum(p<<1,l,mid,x,y);
if(y>mid) res+=querygsum(p<<1|1,mid+1,r,x,y);
pushupg(p);
return res;
}
int findf(int p,int l,int r,int x){
if(l==r){
return l;
}
if(lzf[p])
pushdownf(p,l,r);
int res;
int mid=(l+r)>>1;
if(ffmin[p<<1|1]<=x)
res=findf(p<<1|1,mid+1,r,x);
else
res=findf(p<<1,l,mid,x);
pushupf(p);
return res;
}
int findg(int p,int l,int r,int x){
if(l==r){
return l;
}
if(lzg[p])
pushdowng(p,l,r);
int res;
int mid=(l+r)>>1;
if(ggmin[p<<1]<=x)
res=findg(p<<1,l,mid,x);
else
res=findg(p<<1|1,mid+1,r,x);
pushupg(p);
return res;
}
void solve(){
read(n);
int suma=0;
for(int i=1;i<=n;i++)
read(a[i]),suma+=a[i];
//g[i]+f[i]-n*max(a[1]...a[n])-sigma a[i]
//sigma(1-pos)g[i] + sigma(pos+1,n)f[i]
//f[i+1]>=f[i] g[i]>=g[i+1]
build(1,1,n);
for(int i=1;i<=n;i++){
int ma=querymax(1,1,n,1,i);
modifyf(1,1,n,i,i,ma);
ma=querymax(1,1,n,i,n);
modifyg(1,1,n,i,i,ma);
}
int q;
read(q);
while(q--){
int x,y;
read(x),read(y);
suma+=y;
modify(1,1,n,x,y);
int posvalue=querymax(1,1,n,x,x);
int l=x,r=n;
/*while(l<=r){
int mid=(l+r)>>1;
if(querymax(1,1,n,1,mid)<=posvalue){
l=mid+1;
}
else
r=mid-1;
}*/
r=findf(1,1,n,posvalue);
modifyf(1,1,n,x,r,posvalue);
l=1,r=x;
/*while(l<=r){
int mid=(l+r)>>1;
if(querymax(1,1,n,mid,n)<=posvalue){
r=mid-1;
}
else
l=mid+1;
}*/
l=findg(1,1,n,posvalue);
modifyg(1,1,n,l,x,posvalue);
int res=-n*maxx[1]-suma;
l=1,r=n;
/*while(l<=r){
int mid=(l+r)>>1;
int valuef=queryfsum(1,1,n,mid,mid);
int valueg=querygsum(1,1,n,mid,mid);
if(valuef<=valueg)
l=mid+1;
else
r=mid-1;
}
int pos=r;
if(pos<n)*/
res+=querygsum(1,1,n,1,n);
res+=queryfsum(1,1,n,1,n);
write(res);
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
read(t);
while(t--){
solve();
}
return 0;
}