20210817数论模拟赛
2021/8/18 6:08:24
本文主要是介绍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, 1767263190\cdots\)
递推式:
\[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\n",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\n",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)\n",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\n",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\n",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\n",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\n",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即可。答案为\(\lceil\dfrac n2\rceil\).
对于其余情况:
#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",(n+1)>>1); else{ if(n&1)printf("%d\n",n>>1); else{ n >>= 1; int t = 0; while((1<<t) <= n) t++; t--; n -= 1<<t; printf("%d\n",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\n0 1" : "0");return;} solve(b,c); printf("%lld\n",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
这篇关于20210817数论模拟赛的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南