zoukankan      html  css  js  c++  java
  • 2021.06.12模拟总结

    概述

    端午假期的第一天集训,进行这次组队模拟
    学长:难度 (color{rgb(243, 156, 17)}{橙}spacecolor{rgb(52, 152, 219)}{蓝space蓝})

    T1 立方数(cubicp)

    题意

    给定质数(p),求是否满足(exists a,b),使得(p=a^3-b^3)

    解析

    (p=a^3-b^3)转化一下,得到:

    (p=a^3-b^3space =(a-b) imes(a^2+ab+b^2))
    其中,因为(p)是质数,那么分解出来的两个因数(a-b)(a^2+ab+b^2)一个为(1),一个为(p)
    显然有(|a-b|=1)(a^2+ab+b^2=p)
    所以原式转化为:(b=a+1Rightarrow a^2+acdot(a+1)+(a+1)^2=p)
    得到:(3a^2+3a+1=p)

    由于这样得到的(a)较小,直接枚举(a)即可。
    复杂度(O(Tsqrt p))

    或者,因为(a)的成立性有单调性,可以用二分来优化枚举过程。
    复杂度(O(Tlog{sqrt p}))

    代码

    #include <bits/stdc++.h>
    #define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    const int INF = 0x3f3f3f3f , N = 1e2;
    typedef long long ll;
    typedef unsigned long long ull;
    inline ll read(){
    	ll ret = 0 ; char ch = ' ' , c = getchar();
    	while(!(c >= '0' && c <= '9'))ch = c, c = getchar();
    	while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar();
    	return ch == '-' ? -ret : ret;
    }
    ll check(ll x){return 3*x*x + 3*x + 1;}
    inline bool work(){
    	ll p = read();
    	ll l = 1 , r = 1e9;
    	while(l < r){
    		int mid = (l + r + 1) >> 1;
    		if(check(mid) <= p) l = mid;
    		else r = mid - 1;
    	}
    	return check(l) == p;
    }
    signed main(){
    //	fo("cubicp");
    	int T = read();
    	while(T--)
    		printf("%s
    ",work() ? "YES" : "NO");
    	return 0;
    }
    

    T2 动态规划

    题目名称言简意赅

    题意

    给定长度为(n)序列,分成(k)段,求每段相同数字对数的最小和。

    解析

    很考验思维的一道题,需要用决策单调性优化。
    首先,设(dp[i][j])表示前(i)个数字分为(j)段的最小答案。
    不难得到状态转移方程:(dp[l][r]=dp[l][k]+calc(k+1,r))
    发现方程符合四边形不等式。
    使用类似莫队的方法优化这个过程,
    具体详见代码。(复杂度为(O(nlog n k)))

    一些问题

    • 关于adddel的先加后加问题:
      • Add一个数字(x),对答案的贡献(=)序列内已有的(x)的个数(加入的数和其余数分别组对),所以Add是ans += buc[a[x]]++;
      • Del一个数字(x),对答案的贡献(=)序列内已有的(x)的个数-1(删除的数和其余数分别组队),所以Del是ans -= --buc[a[x]];
    • 关于move的先加后加问题:
      • 区间扩展一个,与上Add
      • 区间减小一个,与上Del
    • 另外:区间移动时倒序比正序略快(不知为何的玄学优化)

    代码

    #include <bits/stdc++.h>
    #define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    const int INF = 0x3f3f3f3f , N = 1e5+5 , M = 22;
    typedef long long ll;
    typedef unsigned long long ull;
    inline ll read(){
    	ll ret = 0 ; char ch = ' ' , c = getchar();
    	while(!(c >= '0' && c <= '9'))ch = c, c = getchar();
    	while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar();
    	return ch == '-' ? -ret : ret;
    }
    int n,k;
    int a[N],buc[N];
    int pl,pr,cur;
    ll ans,dp[N][M];
    inline void add(int x){ans += buc[a[x]]++;}
    inline void del(int x){ans -= --buc[a[x]];}
    inline ll calc(int l,int r){
    	while(pl > l)add(--pl);
    	while(pr < r)add(++pr);
    	while(pl < l)del(pl++);
    	while(pr > r)del(pr--);
    	return ans;
    }
    void dfs(int l,int r,int pl,int pr){
    	if(l > r)return ;
    	int mid = (l + r) >> 1,p;
    	dp[mid][cur] = 1LL*INF*INF;
    	for(int i =  min(mid-1,pr) ; i >= pl ; i --){
    		ll t = dp[i][cur-1] + calc(i+1,mid);
    		if(t < dp[mid][cur])
    			dp[mid][cur] = t,p = i;
    	}
    	dfs(l,mid-1,pl,p);
    	dfs(mid+1,r,p,pr);
    }
    
    signed main(){
    	n = read() , k = read();
    	pl = 1 , pr = 0;
    	for(int i = 1 ; i <= n ; i ++)
    		a[i] = read();
    	for(int i = 1 ; i <= n ; i ++)
    		dp[i][1] = calc(1,i);
    	for(int i = 2 ; i <= k ; i ++)
    		cur = i , dfs(1,n,0,n);
    	printf("%lld",dp[n][k]);
    	return 0;
    }
    

    3.游戏

    题意

    (n)个数字和(T)次给定询问,每次询问给定([l,r])的最小值(x),求第几次操作是矛盾的。

    解析

    对于(T)次询问,可以先进行按(x)从大到小排序。
    对于每一些(x)相同的区间,它们会有交集和并集。维护这个交集和并集。

    • 对于交集:是能确定(x)在的最小的区间,若此段已锁定是更大的值而无处安放,则矛盾
    • 对于并集:是(x)所在最大的区间,也就是上面提到的锁定
      可以维护一个线段树,每个叶节点均为1.若锁定则改为0.
      查询时,找到最区间,判断区间和是否为0即可。
      修改时,找到最区间,修改为0即可。

    复杂度:(O(nlog n log T))

    代码

    #include <bits/stdc++.h>
    #define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    const int INF = 0x3f3f3f3f , N = 1e6;
    typedef long long ll;
    typedef unsigned long long ull;
    inline ll read(){
    	ll ret = 0 ; char ch = ' ' , c = getchar();
    	while(!(c >= '0' && c <= '9'))ch = c, c = getchar();
    	while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar();
    	return ch == '-' ? -ret : ret;
    }
    int n,T;
    struct node{int id,l,r,x;}a[N]; inline bool operator < (node a,node b){return a.x > b.x;}
    
    int tree[N<<2];
    void modify(int k,int l,int r,int x,int y){
    	if(!tree[k])return ;
    	if(x <= l && r <= y){tree[k] = 0;return;}
    	int mid = (l + r) >> 1;
    	if(x <= mid) modify(k<<1,l,mid,x,y);
    	if(y >= mid + 1) modify(k<<1|1,mid+1,r,x,y);
    	tree[k] = tree[k<<1] + tree[k<<1|1];
    }
    int query(int k,int l,int r,int x,int y){
    	if(!tree[k])return 0;
    	if(x <= l && r <= y)return tree[k];
    	int mid = (l + r) >> 1 , ret = 0;
    	if(x <= mid) ret += query(k<<1,l,mid,x,y);
    	if(y >= mid + 1) ret += query(k<<1|1,mid+1,r,x,y);
    	return ret;
    }
    void build(int k,int l,int r){
    	if(l == r) {tree[k] = 1;return;}
    	int mid = (l + r) >> 1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	tree[k] = tree[k<<1] + tree[k<<1|1];
    }
    inline bool check(int x){
    	build(1,1,n);
    	int now = INF , l = INF , r = -INF , cl = -INF , cr = INF;
    	for(int i = 1 ; i <= T ; i ++)
    		if(a[i].id <= x){
    			node f = a[i];
    			if(a[i].x == now){
    				l = min(l,a[i].l);
    				r = max(r,a[i].r);
    				cl = max(cl,a[i].l);
    				cr = min(cr,a[i].r);
    			}
    			else{
    				if(query(1,1,n,cl,cr))
    					modify(1,1,n,l,r);
    				else return 0;
    				now = a[i].x;
    				cl = l = a[i].l , cr = r = a[i].r;
    			}
    		}
    	return query(1,1,n,cl,cr);
    }
    signed main(){
    //	fo("number");
    	n = read() , T = read();
    	for(int i = 1 ; i <= T ; i ++)
    		a[i].l = read() , a[i].r = read() , a[i].x = read() , a[i].id = i;
    	sort(a+1,a+n+1);
    	int l = 1 , r = T;
    	while(l < r){
    		int mid = (l + r + 1)>>1;
    		int tmp;
    		if(tmp = check(mid)) l = mid;
    		else r = mid-1;
    	}
    	printf("%d",l+1);
    	return 0;
    }
    
  • 相关阅读:
    微信 ios端config配置失败 android端正常
    vscode离线安装插件
    win7中vscode会黑屏或者终端空白,无法输入
    vue中使用svg图片
    a.download下载文件 ---跨域问题
    background 背景图片 --css3
    box-shadow
    兄弟伪类
    canvas画时钟
    轮播图--使用原生js的轮播图
  • 原文地址:https://www.cnblogs.com/Shinomiya/p/14878558.html
Copyright © 2011-2022 走看看