The 2023 ICPC Asia Nanjing Regional Contest (The 2nd Universal Cup. Stage 11: Nanjing)

题目链接

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值