快速跳转
题目类型
- A:DP+一点点数论(几乎不用)
- B:最短路+计算几何(判断线段相交)
- C:签到题
- D:图论(tarjan求连通块)
- E:数据结构(线段树)
- F:二分答案
- G:看着像图论,其实构造就行了
- H:数学推导
- I:搜索(标程好像是bfs,但我是用dfsA的)
- J:前缀和+差分
- K:数学
A-Intelligent Warehouse
思路:
给定一组数,选出最多的数,保证其中任意两个数有 a i a_{i} ai是 a j a_{j} aj的因子或 a j a_{j} aj是 a i a_{i} ai的因子。
称选出的最多的数为数群(暂且这么叫,因为其中可以有相同元素,所以不能称作数集)。
考虑DP,对一个数 a i a_{i} ai, d p [ a i ] dp[a_{i}] dp[ai]为满足条件且最大数为 a i a_{i} ai的数群,那么对这个数群中 a i a_{i} ai最大的因子 a j a_{j} aj,必满足数群中 a i a_{i} ai其他的因子也是 a j a_{j} aj的因子,就有 d p [ a i ] = m a x ( d p [ a j ] , d p [ a i ] ) dp[a_{i}]=max(dp[a_{j}],dp[a_{i}]) dp[ai]=max(dp[aj],dp[ai]),然后直接暴力即可。
注意:
选择的数可以有重复,所以要记得计数,比赛时我就是当成数集导致WA了好几次,这个做法刚好没TLE,官方似乎有更快的做法。
#include<bits/stdc++.h>
using namespace std;
const int N=1e7;
int cnt[N+5],dp[N+5];
int main(){
int n,num,ans=0;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&num);
cnt[num]++;
}
for(int i=1;i<=N;i++)
if(cnt[i]){
dp[i]+=cnt[i];
for(int j=i*2;j<=N;j+=i){
dp[j]=max(dp[i],dp[j]);
}
ans=max(ans,dp[i]);
}
cout<<ans;
return 0;
}
B-Intelligent Robot
思路:
注意两点之间直线最短,所以最优路线永远是走线段端点,不需要在线段上走,那么只需要把所有端点(包括起点终点)连接起来,删去相交且交点不在端点的线段,就可以变成最短路问题,然后用dijkstra算法求解
判断线段相交先跨立试验后叉乘,但这题可以直接用叉乘(想一想为什么?)
注意:
这里线段相交,但交点是两线段其中之一的端点的线段不用删去。
#include<bits/stdc++.h>
using namespace std;
const int INF=1e18,N=1e6;
struct edge{
int x1,y1,x2,y2;
}e[N];
struct point{
int x,y;
}p[N];
point operator-(point a,point b){
return (point){
a.x-b.x,a.y-b.y};}
int operator *(const point &a,const point &b)
{
int t=a.x*b.y-b.x*a.y;
return t<0?-1:(t>0);
}
struct heap{
double d;
int u;
bool operator<(const heap& temp) const{
return d>temp.d;
}
};
priority_queue<heap>Q;
bool line(point a1,point a2,point b1,point b2){
return((a2-a1)*(b1-a1))*((a2-a1)*(b2-a1))<0&&((b2-b1)*(a1-b1))*((b2-b1)*(a2-b1))<0;
}
int n,m,k,first[N],qnext[N],v[N],esum=0;
double w[N],d[N];
bool vis[N];
void add(int a,int b,double c){
v[esum]=b;
w[esum]=c;
qnext[esum]=first[a];
first[a]=esum++;
}
int main(){
memset(first,-1,sizeof(first));
cin>>n>>m>>k;
for(int i=1;i<=k;i++){
cin>>e[i].x1>>e[i].y1>>e[i].x2>>e[i].y2;
p[i*2-1].x=e[i].x1,p[i*2-1].y=e[i].y1;
p[i*2].x=e[i].x2,p[i*2].y=e[i].y2;
}
cin>>p[0].x>>p[0].y>>p[2*k+1].x>>p[2*k+1].y;
bool flag;
for(int i=0;i<2*k+1;i++)
for(int j=i+1;j<=2*k+1;j++){
flag=1;
for(int q=1;q<=k;q++)
if(line(p[i],p[j],(point){
e[q].x1,e[q].y1},(point){
e[q].x2,e[q].y2})){
flag=0;
break;
}
if(flag){
double dis=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
v[esum]=j;
w[esum]=dis;
qnext[esum]=first[i];
first[i]=esum++;
v[esum]=i;
w[esum]=dis;
qnext[esum]=first[j];
first[j]=esum++;
}
}
for(int i=1;i<=2*k+1;i++) d[i]=INF;
Q.push((heap){
0,0});
while(!Q.empty()){
heap x=Q.top();
Q.pop();
int u=x.u;
if(vis[u]) continue;
vis[u]=1;
for(int i=first[u];~i;i=qnext[i])
if(d[v[i]]>d[u]+w[i]){
d[v[i]]=d[u]+w[i];
Q.push((heap){
d[v[i]],v[i]});
}
}
printf("%.4f",d[k*2+1]);
return 0;
}
C-Smart Browser
签到题,队友写的,略
D-Router Mesh
思路:
题目很显然是求连通块,用tarjan算法即可
注意:
开始给的图可能不是连通的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define per(i,s,t) for(int i=s;i>=t;i--)
const int N=3e5+5;
int fst[N],nxt[N*2],to[N*2],dfn[N],low[N],ans[N];
int n,m,ti=0,ecnt=0,sum=0,r;
bool vis[N],cut[N];
void add(int x,int y){
nxt[++ecnt]=fst[x];
fst[x]=ecnt;
to[ecnt]=y;
}
void tarjan(int x){
dfn[x]=low[x]=++ti;
int c=0,cnt=0;
for(int i=fst[x];~i;i=nxt[i])
if(!dfn[to[i]]){
tarjan(to[i]);
low[x]=min(low[x],low[to[i]]);
if(low[to[i]]>=dfn[x]){
c++;
cnt++;
if(x!=r||c>1) cut[x]=1;
}
}
else low[x]=min(low[x],dfn[to[i]]);
if(x!=r) cnt++;
ans[x]=cnt;
}
int main(){
cin>>n>>m;
memset(fst,-1,sizeof(fst));
memset(nxt,-1,sizeof(nxt));
// rep(i,1,n) fa[i]=i;
int u,v;
rep(i,1,m){
cin>>u>>v;
add(u,v);
add(v,u);
}
rep(i,1,n)
if(!dfn[i]){
sum++;
tarjan(r=i);
}
rep(i,1,n)
cout<<ans[i]+sum-1<<" ";
return 0;
}
E-Phone Network
思路:
记 R i , j R_{i,j} Ri,j是以j为左端点,包含1~i所以数字的序列的最小右端点,考虑 R i + 1 , j R_{i+1,j} Ri+1,j,令所以i+1的下标为 p 1 , p 2 , . . . , p s p_{1},p_{2},...,p_{s} p1,p2,...,ps,特殊的, p 0 = 0 p_{0}=0 p0=0,那么对于 ( p k − 1 , p k ] (p_{k-1},p_{k}] (pk−1,pk]中的j, R i + 1 , j = m a x ( R i , j , p k ) R_{i+1,j}=max(R_{i,j},p_{k}) Ri+1,j=max(Ri,j,pk),而 ( p s , n ] (p_{s},n] (ps,n]中的j, R i + 1 , j R_{i+1,j} Ri+1,j可记作正无穷。
又由 R i , j R_{i,j} Ri,j是单调的,所以只需在 ( p k − 1 , p k ] (p_{k-1},p_{k}] (pk−1,pk]中找 R i , j < p k R_{i,j}<p_{k} Ri,j<pk的那段j更新值,而 R i , j − j + 1 R_{i,j}-j+1 Ri,j−j+1的最小值即答案。
注意以上操作,有区间赋值和记录区间最小值,因此考虑用线段树处理。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define per(i,s,t) for(int i=s;i>=t;i--)
#define pb push_back
const int INF=0x3f3f3f3f,N=2e5+5;
struct tr{
int l,r,laz,p,d;
}t[N*4];
void down(int x){
if(!t[x].laz) return;
t[x<<1].laz=t[x<<1|1].laz=t[x<<1].p=t[x<<1|1].p=t[x].laz;
t[x<<1].d=t[x].laz-t[x<<1].r+1;
t[x<<1|1].d=t[x].laz-t[x<<1|1].r+1;
t[x].laz=0;
}
void build(int x,int l,int r){
t[x].l=l,t[x].r=r,t[x].d=INF;
if(l==r) return;
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
void chag(int x,int l,int r,int c){
if(l>r||t[x].r<l||t[x].l>r) return;
if(l<=t[x].l&&t[x].r<=r){
t[x].p=t[x].laz=c;
t[x].d=c-t[x].r+1;
return;
}
down(x);
chag(x<<1,l,r,c);
chag(x<<1|1,l,r,c);
t[x].p=min(t[x<<1].p,t[x<<1|1].p);
t[x].d=min(t[x<<1].d,t[x<<1|1].d);
}
int query(int x,int l,int r,int c){
if(l>t[x].r||t[x].l>r||t[x].p>=c) return -1;
if(t[x].l==t[x].r) return t[x].l;
int pos;
pos=query(x<<1|1,l,r,c);
if(pos==-1) pos=query(x<<1,l,r,c);
return pos;
}
int n,m;
vector<int>R[N];
int main(){
cin>>n>>m;
int temp;
build(1,1,n);
rep(i,1,n){
cin>>temp;
R[temp].pb(i);
}
rep(i,1,m){
int np=0,len=R[i].size(),rr;
rep(j,0,len-1){
rr=query(1,np+1,R[i][j],R[i][j]);
chag(1,np+1,rr,R[i][j]);
np=R[i][j];
}
chag(1,np+1,n,INF);
cout<<t[1].d<<" ";
}
return 0;
}
F-Design Problemset
思路:
简单的二分答案,但是中间数据会爆long long,而我又懒得写高精度了,于是找了一个__int128的模板。
注意:
可能会有 Σ l i > R Σl_{i}>R Σli>R或 Σ r i < L Σr_{i}<L Σri<L的情况,直接输出0。
#include<bits/stdc++.h>
using namespace std;
typedef __int128 ll;
typedef double db;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define per(i,s,t) for(int i=s;i>=t;i--)
const int K=1e5+5;
ll a[K],l[K],r[K],k,L,R,sl=0,sr=0,x=0,y=0,ans;
__int128 read(){
__int128 x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1;
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
void print(__int128 x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+'0');
}
bool check(ll m){
ll temp=m*(L-sl),cnt=0;
rep(i,1,k)
if(a[i]<m*l[i]) return 0;
rep(i,1,k)
cnt+=min(a[i]-l[i]*m,(r[i]-l[i])*m);
return cnt>=temp;
}
int main(){
k=read(),L=read(),R=read();
rep(i,1,k){
a[i]=read();
y+=a[i];
}
rep(i,1,k){
l[i]=read(),r[i]=read();
sl+=l[i];
sr+=r[i];
}
if(sl>R||sr<L){
cout<<0;
return 0;
}
while(x<=y){
ll m=(x+y)>>1;
if(check(m)) x=m+1,ans=m;
else y=m-1;
}
print(ans);
return 0;
}
G-Tree Projection
思路:
题目要求一个满足dfs序一个满足topo序,其实都满足topo序即可(想一想为什么?)。而考虑一下topo序的关于边的性质,不难想到,对序列中除了第一个数的任意的一个数 a i a_{i} ai,有且仅有一个 [ 1 , i − 1 ] [1,i-1] [1,i−1]中的数与其连边。
topo序是一个节点的祖先必定排在它的前面,那么倘若不与排在前面的数连边,这个节点就是根节点,而与假如前面的两个数连边,考虑 a i a_{i} ai与 a j a_{j} aj, a i a_{i} ai与 a k a_{k} ak建边,根节点又是 a j a_{j} aj与 a k a_{k} ak的祖先,那么根节点, a i , a j , a k a_{i},a_{j},a_{k} ai,aj,ak四个节点就形成了环,不满足topo序的要求。
而题目只要求输出一种可能,那么就可以考虑这题是构造题。
利用上述的性质,这时候考虑B中每一个B[i],找到B[1~i-1]中在A中下标最小的连边。对A中任意A[i],假设其与A[i-p],A[i-q]相连,A[i-p],A[i-q],A[i]分别对应B[r],B[s],B[t],那么r,s一定在t之前,否则例如r>t>s,那么A[i-q],A[i]均与A[i-p]连边,不会产生假设的情况,而r,s在t之前,按照上述的构造方法,t只会与其中一个连边,也不会产生假设的情况。
因此按照上述的构造方法,本题是一定有解的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define per(i,s,t) for(int i=s;i>=t;i--)
#define push_back pb;
const int N=2e5+5;
int a[N],b,p[N],cnt=0,u[N],v[N];
int main(){
int n;
cin>>n;
rep(i,1,n){
cin>>a[i];
p[a[i]]=i;
}
cin>>b;
int pos=p[b],q=b;
cout<<"YES"<<endl;
rep(i,2,n){
cin>>b;
u[++cnt]=q,v[cnt]=b;
if(p[b]<pos) pos=p[b],q=b;
}
rep(i,1,cnt)
cout<<u[i]<<" "<<v[i]<<endl;
return 0;
}
H-Grouping
我写了最久的题目终于到了
思路:
这是一道推导式子的题目,我和官方题解的推导方法有些差别。
我得到的最终式子是
n − 1 n 2 ( 2 n − 1 ) [ ( 2 n − 1 ) ∑ i = 1 2 n a i 2 − 2 ∑ i = 1 2 n a i ( s 2 n − s i ) ] − 1 n 2 ( 2 n − 1 ) ( 2 n − 3 ) ( [ ∑ i = 1 2 n ( 2 n − i ) a i − ( s 2 n − s i ) ] 2 − ∑ i = 1 2 n [ 2 s i − s 2 n + 2 ( n − i ) a i 2 ] ) \frac{n-1}{n^2(2n-1)}\quad[(2n-1)\sum_{i=1}^{2n}a_{i}^2-2\sum_{i=1}^{2n}a_{i}(s_{2n}-s_{i})]-\frac{1}{n^2(2n-1)(2n-3)}([\sum_{i=1}^{2n}(2n-i)a_{i}-(s_{2n}-s_{i})]^2-\sum_{i=1}^{2n}[2s_{i}-s_{2n}+2(n-i)a_{i}^2]) n2(2n−1)n−1[(2n−1)∑i=12nai2−2∑i=12nai(s2n−si)]−n2(2n−1)(2n−3)1([∑i=12n(2n−i)ai−(s2n−si)]2−∑i=12n[2si−s2n+2(n−i)ai2])
由于草稿纸上太多推错的式子,我也不能确定是不是这个。
推导过程实在太难打了,有兴趣的可以找我。
注意:
到处都取模,能%的都%一下,莫名其妙就过了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define per(i,s,t) for(int i=s;i>=t;i--)
const int N=1e5+5,MOD=998244353;
ll n,a[N*2],s[N*2],s2[N*2];
ll f(ll x){
while(x<0) x+=MOD;
return x;
}
ll sq(ll x){
return (f(x)%MOD*f(x)%MOD)%MOD;
}
ll qpow(int a,int x){
ll ans=1;
while(x){
if(x&1) ans=ans*a%MOD;
a=sq(a);
x>>=1;
}
return ans;
}
int main(){
cin>>n;
int n2=n*2;
rep(i,1,n2) cin>>a[i];
sort(a+1,a+n2+1);
rep(i,1,n2) s[i]=(s[i-1]+a[i])%MOD;
ll f1=0,f2=0,f3=0,f4=0,f5=0;
rep(i,1,n2){
ll tmp=(i*a[i]-s[i]-(2*n-i)*a[i]+(s[n2]-s[i]))%MOD;
f1=(f1+tmp*tmp)%MOD;
f2=(f2+a[i]*a[i]%MOD)%MOD;
f3=(f3+MOD+(-2*n-1+2*i)*a[i]%MOD)%MOD;
}
f4=(n2*f2+MOD-s[n2]*s[n2]%MOD)%MOD;
f5=(f3*f3%MOD+MOD-f1+f4)%MOD;
ll ans,nn=sq(n)*(n2-1)%MOD;
ans=(f(f4*(n-1)%MOD-f5*qpow((n2-3)%MOD,MOD-2))%MOD)*qpow(nn,MOD-2)%MOD;
cout<<f(ans)%MOD;
return 0;
}
I-Walking Machine
思路:
大部分的解法好像都是bfs,但我比赛时是用dfs写的,这题写的比较乱也比较无脑。
注意:
记得考虑n=m=1时候,如果是考虑四角的话会把这个点重复算四遍。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5,M=1e3+5;
int n,m,ans=0;
char a[N][N];
bool vis[N][N];
void dfs(int x,int y){
if(!vis[x][y]) vis[x][y]=1;
else return;
ans++;
if(x+1<=n&&a[x+1][y]=='W')
dfs(x+1,y);
if(x-1>0&&a[x-1][y]=='S')
dfs(x-1,y);
if(y+1<=m&&a[x][y+1]=='A')
dfs(x,y+1);
if(y-1>0&&a[x][y-1]=='D')
dfs(x,y-1);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
if(a[1][1]=='W'||a[1][1]=='A')
dfs(1,1);
if(a[1][m]=='W'||a[1][m]=='D')
dfs(1,m);
if(a[n][1]=='S'||a[n][1]=='A')
dfs(n,1);
if(a[n][m]=='S'||a[n][m]=='D')
dfs(n,m);
for(int i=2;i<m;i++){
if(a[1][i]=='W')
dfs(1,i);
if(a[n][i]=='S')
dfs(n,i);
}
for(int i=2;i<n;i++){
if(a[i][1]=='A')
dfs(i,1);
if(a[i][m]=='D')
dfs(i,m);
}
cout<<ans;
return 0;
}
J-Matrix Subtraction
思路:
由于是比赛时候做的所以只记得是用二维前缀和及差分。
考虑到用这个了应该就很容易写出来了
#include<bits/stdc++.h>
using namespace std;
int t,n,m,a,b,c[1005][1005],p[1005][1005];
bool f(int x,int y){
int s1=c[x-1][y]+c[x][y-1]-c[x-1][y-1],s2=0;
if(x>=a) s2+=c[x-a][y];
if(y>=b) s2+=c[x][y-b];
if(x>=a&&y>=b) s2-=c[x-a][y-b];
if(s1-s2>p[x][y]) return 0;
else if(s1-s2<p[x][y]){
if(x>n-a+1||y>m-b+1) return 0;
c[x][y]=s1+p[x][y]-(s1-s2);
}
else c[x][y]=s1;
return 1;
}
void op(){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!f(i,j)){
cout<<"QAQ"<<endl;
return;
}
cout<<"^_^"<<endl;
}
int main(){
cin>>t;
while(t--){
cin>>n>>m>>a>>b;
memset(p,0,sizeof(p));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>p[i][j];
op();
}
return 0;
}
K-Sqrt Approaching
终于到了数学类题目
思路:
将题目进行简单的转化,就变成要找C,D满足 C D \frac{C}{D} DC在 n \sqrt{n} n与 A B \frac{A}{B} BA之间,而题目又是只需要输出一组解,所以尝试构造解。
由于我的解法和官方解法不同,所以其实样例的输出也和我的输出不同,官方解法直接给出构造,未免有点无中生有的感觉,我尝试给出得到构造的思路。
首先观察一下A,B,C,D,n的数据范围,不难猜想构造出的C,D应该可能含有nA,nB,A,B,n和常数项。而 A B \frac{A}{B} BA是有理数, n \sqrt{n} n是无理数,如果构造的 C D \frac{C}{D} DC在他们之间,那么一直重复这个构造方法,就会越来越逼近 n \sqrt{n} n,即找到一种迭代方法,不断逼近它。
其实这里我考虑过牛顿迭代法,但是构造出的A有二次项,于是换一种思路。
令 t = A B t=\frac{A}{B} t=BA,那么要做的其实是找到一个递推式形如 x n + 1 = ( p 1 n + p 2 ) x n + p 3 n + p 4 ( q 1 n + q 2 ) x n + q 3 n + q 4 x_{n+1}=\frac{(p_{1}n+p_{2})x_{n}+p_{3}n+p_{4}}{(q_{1}n+q_{2})x_{n}+q_{3}n+q_{4}} xn+1=(q1n+q2)xn+q3n+q4(p1n+p2)xn+p3n+p4的数列,其极限是 n \sqrt{n} n,其中p,q都是整数,这时候分子分母就是C,D了。
那么这时我们对两边取极限(不考虑严谨性,就先假设存在了),即
n = ( p 1 n + p 2 ) n + p 3 n + p 4 ( q 1 n + q 2 ) n + q 3 n + q 4 \sqrt{n}=\frac{(p_{1}n+p_{2})\sqrt{n}+p_{3}n+p_{4}}{(q_{1}n+q_{2})\sqrt{n}+q_{3}n+q_{4}} n=(q1n+q2)n+q3n+q4(p1n+p2)n+p3n+p4,整理一下可以得到
q 1 n 2 + ( q 3 − p 1 ) n n + ( q 2 − p 3 ) n + ( q 4 − p 2 ) n − p 4 = 0 q_{1}n^2+(q_{3}-p_{1})n\sqrt{n}+(q_{2}-p_{3})n+(q_{4}-p_{2})\sqrt{n}-p_{4}=0 q1n2+(q3−p1)nn+(q2−p3)n+(q4−p2)n−p4=0
若该式子恒成立,那么必有 q 1 = p 4 = 0 , q 3 = p 1 , q 2 = p 3 , q 4 = p 2 q_{1}=p_{4}=0,q_{3}=p_{1},q_{2}=p_{3},q_{4}=p_{2} q1=p4=0,q3=p1,q2=p3,q4=p2
而 q 2 , p 3 q_{2},p_{3} q2,p3首先保证不为0,否则式子将与t无关,那么为了简化式子,不妨考虑下 q 4 = p 2 = 0 q_{4}=p_{2}=0 q4=p2=0,代回原式得到 x n + 1 = p 1 n x n + p 3 n p 3 x n + p 1 n x_{n+1}=\frac{p_{1}nx_{n}+p_{3}n}{p_{3}x_{n}+p_{1}n} xn+1=p3xn+p1np1nxn+p3n
那么就初步构造出 C D = p 1 n t + p 3 n p 3 t + p 1 n \frac{C}{D}=\frac{p_{1}nt+p_{3}n}{p_{3}t+p_{1}n} DC=p3t+p1np1nt+p3n,不妨设 t = A B > n t=\frac{A}{B}>\sqrt{n} t=BA>n,那么就有 t = A B > C D > n t=\frac{A}{B}>\frac{C}{D}>\sqrt{n} t=BA>DC>n,先考虑 C D > n \frac{C}{D}>\sqrt{n} DC>n,可以得到 p 1 n − ( p 1 t + p 3 ) n + p 3 t < 0 p_{1}n-(p_{1}t+p_{3})\sqrt{n}+p_{3}t<0 p1n−(p1t+p3)n+p3t<0,即 t ( p 1 n − p 3 ) > n ( p 1 n − p 3 ) t(p_{1}\sqrt{n}-p_{3})>\sqrt{n}(p_{1}\sqrt{n}-p_{3}) t(p1n−p3)>n(p1n−p3),那么只需要 p 1 n − p 3 > 0 p_{1}\sqrt{n}-p_{3}>0 p1n−p3>0恒成立即 n > p 1 p 3 \sqrt{n}>\frac{p_{1}}{p_{3}} n>p3p1。
这时候考虑最简单的形式即 p 1 = p 3 = 1 p_{1}=p_{3}=1 p1=p3=1,带入发现满足题意,所以就可以得到了构造C=n(A+B),D=A+nB,然后就是一些高精度计算了。
我还考虑过 q 3 = p 1 = 0 q_{3}=p_{1}=0 q3=p1=0,但是并不可行。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define per(i,s,t) for(int i=s;i>=t;i--)
const int L=1e5+20;
ll a[L],b[L],na[L],nb[L],c[L],d[L],n;
void read(ll p[],string q){
p[0]=q.size();
per(i,(p[0]-1),0)
p[p[0]-i]=q[i]-'0';
}
void muln(ll p[],ll q[]){
rep(i,1,p[0])
q[i]=n*p[i];
int temp,k;
rep(i,1,p[0]){
temp=q[i]/10,k=1,q[i]%=10;
while(temp)
q[i+k]+=temp%10,temp/=10,k++;
}
q[0]=p[0]+k-1;
}
void add(ll p[],ll q[],ll r[]){
r[0]=max(p[0],q[0]);
rep(i,1,r[0])
r[i]+=p[i]+q[i],r[i+1]+=r[i]/10,r[i]%=10;
if(r[r[0]+1]) r[0]++;
}
int main(){
string A,B;
cin>>A>>B>>n;
read(a,A),read(b,B);
muln(a,na),muln(b,nb);
add(na,nb,c);
add(a,nb,d);
per(i,c[0],1) cout<<c[i];
cout<<endl;
per(i,d[0],1) cout<<d[i];
return 0;
}
以及附上我看见别人这题的python代码…
A=input()
B=input()
n=input()
print(A*n+B*n)
print(A+B*n)