• 20210817数论模拟赛


    数论啊!

    赛时

    知道考数论后很慌,这里基本停留在只能看懂题解的程度……
    开题,果然发现一道题都不会QAQ

    看到T1认为一定有规律。手推了(1h)后发现了(错误)的规律,打表并输出。

    T2感觉可做,在写完T1后来想这道题。

    可以确定:最佳决策点一定是经过某条线段的端点的。

    于是想到(O(n^3))的暴力:枚举两条线段,用斜截式(y=kx+b)确定此时的直线,再枚举线段判断是否有交。

    期望得分:(50).

    赛后:发现问题出在:(y=kx+b)不能表示与(y)轴平行直线!导致挂(10pts).

    T3和T4不太会,这里见下面吧。

    赛后

    T1:卡特兰数

    以前并不知道这个名词。

    数列大致如下:

    (1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190cdots)

    递推式:

    [H_n= dfrac{H_{n-1}cdot(4n-2)}{n+1}. ]

    注意分母要求逆元。

    #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 = 2e5+5 , mod = 1e9+7;
    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;
    ll a[N],inv[N];
    void init(){
    	inv[1] = 1;
    	for(int i = 2 ; i <= 2e5+1 ; i ++)
    		inv[i] = ((mod-mod/i*inv[mod%i])%mod+mod)%mod;
    	a[1] = 1;
    	for(int i = 2 ; i <= 2e5 ; i ++)
    		a[i] = ((a[i-1] * (4*i-2))%mod*inv[i+1]+mod)%mod;
    }
    void work(){
    	n = read();
    	printf("%d
    ",a[n]);
    }
    signed main(){
    //	fo("notitle");
    	int T = read();
    	init();
    	while(T--)
    		work();
    }
    

    T2

    思路是对的,考虑优化:

    寻找线段中的一个点作为基准点,处理出其他点到基准点的斜率(k)为避免以上出现的问题,将斜率转化为(dfrac1k)处理

    后离散化,转化为"区间修改+区间查询最大值"。

    使用线段树。

    注意细节。

    #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 = 1e3+5;
    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;
    struct node{int x1,x2,y;ll v;}a[N];
    inline bool operator < (const node a,const node b){return a.y < b.y;}
    ll tree[N<<4],lazy[N<<4],ans = -INF;
    inline void Add(int k,int l,int r,ll v){
    	lazy[k] += v;
    	tree[k] += v;
    }
    inline void pushdown(int k,int l,int r){
    	if(!lazy[k])return;
    	int mid = (l + r) >> 1;
    	Add(k<<1,l,mid,lazy[k]);
    	Add(k<<1|1,mid+1,r,lazy[k]);
    	lazy[k] = 0;
    }
    void modify(const int k,const int l,const int r,const int x,const int y,const ll v){
    	if(x <= l && r <= y) {Add(k,l,r,v);return;}
    	int mid = (l + r) >> 1;
    	pushdown(k,l,r);
    	if(x <= mid)modify(k<<1,l,mid,x,y,v);
    	if(y > mid)modify(k<<1|1,mid+1,r,x,y,v);
    	tree[k] = max(tree[k<<1],tree[k<<1|1]);
    //	printf("  Tree[%d] : [%d,%d] : %lld
    ",k,l,r,tree[k]);
    }
    ll query(const int k,const int l,const int r,const int x,const int y){
    	if(x <= l && r <= y) return tree[k];
    	int mid = (l + r) >> 1;
    	ll ret = 0;
    	pushdown(k,l,r);
    	if(x <= mid) ret = max(ret,query(k<<1,l,mid,x,y));
    	if(y > mid) ret = max(ret,query(k<<1|1,mid+1,r,x,y));
    	return ret;
    } 
    
    double d[N][2],p[N<<2];
    int vis[N],cnt;
    void build(int u,int x){
    	memset(tree,0,sizeof(tree)),memset(lazy,0,sizeof(lazy));
    	cnt = 0;
    //	printf("Start from (%d,%d)
    ",x,a[u].y);
    	for(int i = 1 ; i <= n ; i ++)
    		if(i != u && a[i].y != a[u].y)
    			vis[i] = u,
    			d[i][0] = p[++cnt] = 1.0*(x-a[i].x1)/(a[u].y-a[i].y),
    			d[i][1] = p[++cnt] = 1.0*(x-a[i].x2)/(a[u].y-a[i].y);
    	sort(p+1,p+cnt+1);
    	int tot = unique(p+1,p+cnt+1)-p-1;
    //	printf("tot = %d
    ",tot);
    	for(int i = 1 ; i <= n ; i ++)
    		if(i != u && vis[i] == u){
    			int l = lower_bound(p+1,p+tot+1,d[i][0])-p,
    				r = lower_bound(p+1,p+tot+1,d[i][1])-p;
    			ll  v = a[i].v;
    			if(l > r)swap(l,r),swap(d[i][0],d[i][1]);
    //			printf("   (%d,%d)(%d) -> (%d->%d) as (%.2lf -> %.2lf) : %lld
    ",a[i].x1,a[i].x2,a[i].y,l,r,d[i][0],d[i][1],v);
    			modify(1,1,tot,l,r,v);
    		}
    	ans = max(ans,query(1,1,n,1,n)+a[u].v);
    //	printf("  now ans = %lld
    ",ans);
    }
    signed main(){
    //	fo("oil");
    	n = read();
    	for(int i = 1 ; i <= n ; i ++) {
    		a[i].x1 = read() , a[i].x2 = read();
    		if(a[i].x1 > a[i].x2)swap(a[i].x1,a[i].x2);
    		a[i].y = read() , a[i].v = a[i].x2 - a[i].x1;
    	}
    	sort(a+1,a+n+1); 
    //	for(int i = 1 ; i <= n ; i ++)
    //		printf("  %d:(%d,%d)->(%d,%d),%lld
    ",i,a[i].x1,a[i].y,a[i].x2,a[i].y,a[i].v);
    	
    	for(int i = 1 ; i <= n ; i ++){
    		build(i,a[i].x1);
    		build(i,a[i].x2);
    	}
    	
    	printf("%lld",ans);
    	return 0;
    }
    

    T3

    一道博弈论题。

    对于(S = {1})的情况,直接给所有同奇偶性编号的分发1即可。答案为(lceildfrac n2 ceil).

    对于其余情况:

    #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 = 1e3+5;
    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 n,s;
    void work(){
    	n = read() , s = read();
    	if(s)
    		printf("%d
    ",(n+1)>>1);
    	else{
    		if(n&1)printf("%d
    ",n>>1);
    		else{
    			n >>= 1;
    			int t = 0;
    			while((1<<t) <= n)
    				t++;
    			t--;
    			n -= 1<<t;
    			printf("%d
    ",n);
    		}
    	}
    }
    signed main(){
    //	fo("distribute");
    	int T = read();
    	while(T--)
    		work();
    }
    

    T4

    感觉推不太明白这道题,这里放上题解做法吧……

    #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 = 1e3+5;
    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 a,b,c;
    ll ans,w[110];
    int tot;
    bool solve(ll fa,ll fb){
    	if(!fa && !fb){ans ++;return 1;}
    	if(!fa || !fb) return 0;
    	
    	ll v = fb % b;
    	if(v)
    		if(!((fa - v) % a)){
    			w[++tot] = v;
    			return solve((fa-v)/a,(fb-v)/b);
    		}
    		else return 0;
    	else{
    		bool flag = 0;
    		int pos = ++tot;
    		if(!(fa % a))
    			w[pos] = 0,
    			flag = solve(fa/a,fb/b);
    		if(fa == b && fb == b){
    			ans ++;
    			if(!flag)
    				w[pos] = b,
    				tot = pos;
    			return 1;
    		}
    		return flag;
    	}
    }
    void work(){
    	a = read() , b = read() , c = read();
    	tot = -1;
    	ans = 0;
    	if(b == 1){puts(c == 1 ? a == 1 ? "-1" : "1
    0 1" : "0");return;}
    	
    	solve(b,c);
    	printf("%lld
    ",ans);
    	if(!ans)return;
    	if(tot == -1)
    		tot = 0,w[0] = b;
    	
    	printf("%d ",tot);
    	for(int i = tot ; i >= 0 ; i --)
    		printf("%lld ",w[i]);
    	puts("");
    }
    signed main(){
    //	fo("polynomial");
    	int T = read();
    	while(T--)
    		work();
    }
    

    集训第二阶段就剩一天了,加油QAQ

  • 相关阅读:
    第三百六十九天 how can I 坚持
    第三百六十八天 how can I 坚持
    第三百六十四、五、六、七天 how can I 坚持
    POJ 1663:Number Steps
    POJ 2676:Sudoku 数独
    POJ 2488:A Knight's Journey 深搜入门之走马观花
    POJ 3050:Hopscotch
    51nod 1419:最小公倍数挑战
    POJ 1011:Sticks 经典搜索
    POJ 2362:Square 觉得这才算深度搜索
  • 原文地址:https://www.cnblogs.com/Shinomiya/p/15154898.html
Copyright © 2020-2023  润新知