首页 > 其他分享 >noip模拟2

noip模拟2

时间:2024-07-10 19:34:57浏览次数:13  
标签:noip int sum long using now 模拟 define

赛时rank10,T1 100,T2 0,T3 5,T4 100

T2的部分分懒得打了,T3特判的5分,也是没有打暴力。

T1,T4签到题

T1 酸碱度中和

二分加贪心的水题,时间复杂度\(O(n\log V)\)

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
#define int long long
const int N = 1e5 + 10;
int n,k,a[N];
inline bool check(int mid){
    int res = 0,last = 0;
    for(int i = 1;i <= n; ++i){
        while(i <= n){
            int midd = (a[i]+a[last+1])/2;
            if(max(abs(a[last+1]-midd),abs(a[i]-midd)) <= mid) i++;
            else break;
        }
        i--;
        int midd = (a[i]+a[last+1])/2;
        if(max(abs(a[last+1]-midd),abs(a[i]-midd)) <= mid) res++,last = i;
    }
    if(last != n) return false;
    return res <= k;
}
signed main(){
    #ifndef ONLINE_JUDGE
        infile("in.in");outfile("out.out");
    #else
    #endif
    cin.tie(nullptr)->sync_with_stdio(false);
    cout.tie(nullptr)->sync_with_stdio(false);
    cin>>n>>k;
    for(int i = 1;i <= n; ++i) cin >> a[i];
    sort(a + 1,a + 1 + n);
    int l = 0,r = a[n],ans = 0;
    while(l <= r){
        int mid = (l + r) >> 1;
        if(check(mid)) ans = mid,r = mid-1;
        else l = mid + 1;
    }
    cout<<ans;
}

T2 聪明的小明

状压难题。

暴力搜索加特殊性质可以拿到30pts的高分,但由于懒,就没打。

由于\(k\)和\(m\)很小,考虑状压。

将每一种U8酒最后出现的位置设为1,其余全部为0,则112332记作010011,将其状压,则所有的二进制数中,1的个数恰好为k且最后一位为1的状态都是合法的。

设\(f_{i,S}\)表示以第\(i\)位为结尾,后\(m\)位的状态数为\(S\)的方案数,设上一位能够转移到的状态为\(S^\prime\),则\(f_{i,S}=\sum f_{i-1,S^\prime}\)

对于每一种状态\(S\),其合法的状态有很多,计算方式如下:

  • 设\(res\)为方案数,\(num\)为当前已经枚举到的1的个数,从后往前枚举,若遇到一个1,则\(res\times=(k-num)\)

dp转移分情况讨论

  1. 若状态的第1位为1,则\(f_{i+1,j<<1|1}+=f_{i,j}\)
  2. 若状态的第1位位0,则\(f_{i+1,j<<1}+=f_{i,j},f_{i+1,(j\,xor\,x)<<1|1}+=f_{i,j}(x\in \{2^k\}(2^k\le j))\)

转移即可

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
const int N = 1e5 + 10,mod = 998244353;
ll f[N][1<<10];
int n,m,k;
vector<int> sta;
inline int get(int x){
    // cerr<<x<<'\n';
    int res = 1,num = 0;
    for(int i = 1<<(m-1);i>0;i >>= 1) res *= k-num,num += (bool)(x&i),res %= mod;
    return res;
}
signed main(){
    // #ifndef ONLINE_JUDGE
    //     infile("in.in");outfile("out.out");
    // #else
    // #endif
    cin.tie(nullptr)->sync_with_stdio(false);
    cout.tie(nullptr)->sync_with_stdio(false);
    cin>>n>>k>>m;
    int ed = (1<<m);
    for(int i = 0;i < ed; ++i) 
        if(__builtin_popcount(i) == k && (i&1)) sta.push_back(i);
    for(auto i : sta) f[m][i] = get(i);
    for(int i = m;i < n; ++i){
        for(auto j : sta){
            bool flag = j&(1<<m);
            if(flag) f[i+1][(j<<1)|1] = (f[i+1][(j<<1)|1]+f[i][j])%mod;
            else{
                (f[i+1][j<<1] += f[i][j])%=mod;
                for(int x = 1;x <= j; x <<= 1) 
                    if(j&x) (f[i+1][((j^x)<<1)|1] += f[i][j])%=mod;
            }
        }
    }
    ll ans = 0;
    for(auto j : sta) ans = (ans + f[n][j]) % mod;
    cout<<ans;
}

T3 线段树

赛时想过区间dp,但不会打……

\(f_{l,r}\)下界显然为1,那么什么时候它的下界可以加1?

对于当前查询区间\([l,r]\),在线段树上有一个区间\([L,R]\),从\(k\)处划分该区间,若\([L,R]\)与\([l,r]\)有交且互不包含,且\([l,r]\)经过\(k+0.5\),则必须要走\([L,R]\)的两颗子树,下界加一。

设\(dp_{i,j}\)表示在线段树上的一个区间\([i,j]\)其子树内产生的贡献的最小值。则有

\[dp_{i,j}=\min_{k=i}^{j-1}\{dp_{i,k}+dp_{k,j}+sum(i,j,k)\} \]

\(sum(i,j,k)\)表示与区间\([i,j]\)有交且互不包含,经过\(k+0.5\)的查询区间个数。

考虑如何查询这个东西。

设\(w1_k\)表示经过\(k+0.5\)的位置的区间个数,\(w2_{l,r}\)表示包含区间\([l,r]\)的查询区间个数。
有\(num(l,r,k)=w1_k-w2_{l,r}\)

求\(w1\)是水,考虑如何求\(w2\)。

考虑使用二维前缀和,\(w2_{l,r} = w2_{l,r}+w2_{l-1,r}+w2_{l,r+1}-w2_{l-1,r+1}\)

然后就可以了

场上就是没有想到w2,然后就没打……

\(CaI_2\)

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
const int N = 510;
ll f[N][N],n,q,sum[N][N],w[N];
signed main(){
    #ifndef ONLINE_JUDGE
        infile("in.in");outfile("out.out");
    #else
    #endif
    cin.tie(nullptr)->sync_with_stdio(false);
    cout.tie(nullptr)->sync_with_stdio(false);
    cin>>n>>q;
    for(int i = 1,l,r;i <= q; ++i){
        cin>>l>>r;sum[l][r]++;
        w[l]++,w[r]--;
    }
    for(int i = 1;i <= n; ++i) w[i] += w[i-1];
    for(int len = n - 1;len >= 1; --len){
        for(int l = 1;l + len - 1 <= n; ++l){
            int r = l + len - 1;
            sum[l][r] = sum[l][r] + sum[l-1][r] + sum[l][r+1] - sum[l-1][r+1];
        }
    }
    for(int len = 2;len <= n; ++len){
        for(int l = 1;l + len - 1 <= n; ++l){
            int r = l + len - 1;
            f[l][r] = LLONG_MAX;
            for(int k = l;k < r; ++k){
                f[l][r] = min(f[l][r],f[l][k]+f[k+1][r]+w[k]-sum[l][r]);
            }
        }
    }
    cout<<f[1][n]+q<<'\n';
}

T4 公路

简单题,贪心即可。

设当前位置为\(now\),它能走到的最远位置为\(max\),假设这段区间内有比当前位置的花费小的位置\(y\),则在此处加油,直至恰好走到\(y\)。若没有,在当前位置加满油,找出区间内最小的位置\(y\),走到这个位置即可。可以用单调队列维护,也可以用ST表、线段树维护。

单调队列:(come from wang54321)

点此查看代码
#include<bits/stdc++.h>
#define llt long long
const llt N=100010;
const llt mod=998244353;
using namespace std;
llt n,C,cnow,v[N],c[N],ans;
deque<llt>  L,P;
int main()
{
    #ifdef  LOCAL
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    scanf("%lld%lld",&n,&C);
    for(int i=2;i<=n+1;i++)   scanf("%lld",&v[i]);
    for(int i=1;i<=n;i++)   scanf("%lld",&c[i]),c[n+1]=0;
    for(int i=1;i<=n+1;i++)   
    {
        cnow-=v[i];
        while(!P.empty()&&L.front()<=v[i])   v[i]-=L.front(),L.pop_front(),P.pop_front();
        L.front()-=v[i];
        while(!P.empty()&&P.back()>=c[i])    cnow-=L.back(),ans-=L.back()*P.back(),L.pop_back(),P.pop_back();
        ans+=(C-cnow)*c[i];
        P.push_back(c[i]),L.push_back(C-cnow);
        cnow=C;
    }
    printf("%lld\n",ans);
    return 0;
}

ST表:

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
#define int long long
const int N = 1e5 + 10;
int n,c,v[N],a[N];
#define mk make_pair
pair<int,int> st[18][N];
inline void pre(){
    for(int i = 1;i <= n; ++i) st[0][i] = mk(a[i],i);
    int t = log2(n) + 1;
    for(int j = 1;j <= t; ++j){
        for(int i = 1;i + (1<<j) - 1 <= n; ++i){
            st[j][i] = min(st[j-1][i],st[j-1][i+(1<<(j-1))]);
        }
    }
}
inline pair<int,int> query(int l,int r){
    int k = log2(r-l+1);
    return min(st[k][l],st[k][r-(1<<k)+1]);
}
signed main(){
    #ifndef ONLINE_JUDGE
        infile("in.in");outfile("out.out");
    #else
    #endif
    cin.tie(nullptr)->sync_with_stdio(false);
    cout.tie(nullptr)->sync_with_stdio(false);
    cin>>n>>c;
    for(int i = 2;i <= n + 1; ++i) cin>>v[i];
    for(int i = 1;i <= n; ++i) cin>>a[i];
    for(int i = 2;i <= n + 1; ++i) v[i] += v[i - 1];
    pre();
    ll ans = 0;
    int nxxt = 1,now = 1,res = 0;
    while(now<=n){
        while(nxxt <= n+1 && v[nxxt] - v[now] <= c){
            nxxt++;
            if(a[nxxt-1] < a[now]) break;
        }
        nxxt--;
        if(now == n){
            ans += (v[n+1]-v[n]-res)*a[now];
            res = 0;break;
        }
        pair<int,int> emm = query(min(now+1,n),min(nxxt,n));
        int mnval = emm.first,mnpos = emm.second;
        if(nxxt == n + 1){
            if(mnval < a[now]){
                ans += (v[mnpos]-v[now]-res)*a[now];
                now = mnpos;
                res = 0;
                continue;
            }
            else{
                ans += (v[n+1]-v[now]-res)*a[now];
                now = n+1;
                res = 0;
                break;
            }
        }
        else{
            if(mnval < a[now]){
                ans += (v[mnpos]-v[now]-res)*a[now];
                now = mnpos;
                res = 0;
                continue;
            }
            else{
                ans += (c-res)*a[now];
                res = c-(v[mnpos]-v[now]);
                now = mnpos;
                continue;
            }
        }
    }
    cout<<ans;
}

线段树:(from abnormal123)

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+100,INF=1e9;
int n,c,v[N],a[N],sum[N],oil,mon;
struct node{
	int id,va;
}t[N<<2];
void pushup(int rt){
	if(t[rt<<1].va<=t[rt<<1|1].va){
		t[rt].va=t[rt<<1].va;
		t[rt].id=t[rt<<1].id;
	}
	else{
		t[rt].va=t[rt<<1|1].va;
		t[rt].id=t[rt<<1|1].id;
	}
}
void build(int rt,int l,int r){
	if(l==r){
		t[rt].id=l;
		t[rt].va=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}
int get(int x){
	int l=1,r=n;
	if(sum[n]<=x)return n-1;
	while(l<r){
		int mid=(l+r)>>1;
		if(sum[mid]<=x)l=mid+1;
		else r=mid;
	}
	return l-1;
}
node query(int rt,int l,int r,int L,int R){
	if(L<=l&&r<=R)return t[rt];
	int mid=(l+r)>>1;
	node x={INF,INF},y={INF,INF} ;
	if(mid>=L)x=query(rt<<1,l,mid,L,R);
	if(mid+1<=R)y=query(rt<<1|1,mid+1,r,L,R);
	if(x.va<=y.va)return x;
	else return y;
}
signed main()
{
	// freopen("q.in","r",stdin);
	// freopen("q.out","w",stdout);	
	scanf("%lld%lld",&n,&c);
	for(int i=0;i<n;i++){
		scanf("%lld",&v[i]);
		sum[i+1]=sum[i]+v[i];
	}
	for(int i=0;i<n;i++){
		scanf("%lld",&a[i]);
	}
	build(1,0,n-1);
	int i;
	for(i=0;i<n;){
		int to=get(sum[i]+c),now=i;
		if(i+1==n){
			if(oil<sum[n]-sum[i]){
				mon+=(sum[n]-sum[i]-oil)*a[i];
			}
			break;
		}
		node minn=query(1,0,n-1,i+1,to);
		if(minn.va<=a[now]){
			while(a[++i]>a[now]&&i<n);
			if(oil>=sum[i]-sum[now])oil-=(sum[i]-sum[now]);
			else {
				mon+=(sum[i]-sum[now]-oil)*a[now];
				oil=0;
			}
		}
		else if(sum[i]+c>=sum[n]){
			if(oil<sum[n]-sum[now]){
				mon+=(sum[n]-sum[now]-oil)*a[now];
			}
			break;
		}
		else{
			i=minn.id;
			mon+=(c-oil)*a[now];
			oil=c-(sum[i]-sum[now]);
		}
	}
	cout<<mon<<endl;
}

糖丸了,每次模拟赛都是赛时想到了正解然后要么不会打,要么自己给自己否了。
dp学的不行,主要是推不出柿子,还是要多练。

标签:noip,int,sum,long,using,now,模拟,define
From: https://www.cnblogs.com/hzoi-Cu/p/18294122

相关文章

  • 模拟增益(Analog Gain)、数字增益(Digital Gain)
    在WebRTC中,模拟增益和数字增益是两种增强音频信号的技术,它们在确保通话质量中扮演着重要角色。下面我将详细解释这两种增益的概念及其作用。模拟增益(AnalogGain)模拟增益是在模拟信号处理阶段调整信号强度的过程。模拟增益通常在音频信号被转换为数字信号之前,在麦克风放大器级别......
  • NOIP2005 普及:第三题 采药
    辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你......
  • 题解与求助 P2347 [NOIP1996 提高组] 砝码称重
    P2347[NOIP1996提高组]砝码称重题目描述设有$1\mathrm{g}$、$2\mathrm{g}$、$3\mathrm{g}$、$5\mathrm{g}$、$10\mathrm{g}$、$20\mathrm{g}$的砝码各若干枚(其总重$\le1000$),可以表示成多少种重量?输入格式输入方式:$a_1,a_2,a_3,a_4,a_5,a_6$(表示$1\mathrm{......
  • CSP-J1 CSP-S1 第1轮 初赛模拟题及书籍
    1、信奥学奥赛一本通初赛篇信息学奥赛一本通(C++版)在线评测系统15*2=30套模拟题(CSP-J115套、CSP-S115套)2、信息学奥赛CSP满分之路——CSP-JS第一轮原创全真模拟试卷集(2024)图灵社区20套模拟题(10套CSP-J+10套CSP-S)        普及组 CSP-J2024......
  • 7.9构造、模拟、转换
    1.MathematicalProblem题意给定奇数\(n\),求出\(n\)个长度为\(n\)的完全平方数满足:组成这\(n\)个数的数字(\([0,9]\)内数字)组成的可重集相同。输出任意一种方案。思路进行打表\(n=3\)-->\(169,196,961\)\(n=5\)-->\(16900,19600,96100,10609,90601\)发现规律每......
  • 2024/7/9 noip模拟鳃
    T130pts教训:存图双向边数组要开2倍(就是这么简单!)还害得我调了半个小时才发现,改后accode:usingnamespacestd;intn,a,b,anode,bnode;constintmaxn=1e6+10;structedge{ intto,next;}e[maxn];intnodeflag=-1;inthead[maxn],siz[maxn],cnt,ans[maxn];voidadd......
  • 洛谷P5594 【XR-4】模拟赛C语言
    #include<stdio.h>intmain(){ intn,m,k; inti,j; inth,l; scanf("%d%d%d",&n,&m,&k); intarr[n+1][m+1]; intday[k+1]; for(i=1;i<=n;i++){//录入数据 for(j=1;j<=m;j++){ scanf("%d&quo......
  • 洛谷P1308 [NOIP2011 普及组] 统计单词数C语言
    #include<stdio.h>#include<string.h>#include<ctype.h>intmain(){charcheck[11];charstr[1000001];intf_num=0;intcount=0;inti=0;intj=0;intp=1;gets(check);gets(str);......
  • 浅谈 [NOIP 2023]三值逻辑 无限种解法
    浅谈[NOIP2023]三值逻辑无限种解法前言对于NOIP2023,T1是个人人都会写的签到题,对于T3则是做法唯一只能按照提醒的数据范围一步一步走,对于T4则是只能线段树优化dp。思维局限性大,并没有什么深度挖掘的意义。直到有一天睡觉的时候又想起来T2这个题,觉得有必要把这个题相......
  • Noah-MP陆面生态水文模拟与多源遥感数据同化
    陆面模型在生态水文研究中的地位和作用;熟悉模型的发展历程,常见模型及各自特点;理解Noah-MP模型的原理,掌握Noah-MP模型在单站和区域的模拟、模拟结果的输出和后续分析及可视化等方法;课程还将深入讲解数据同化的原理与应用。原文链接......