C-Circle_河南萌新联赛2024第(三)场:河南大学 (nowcoder.com)
对于该题,样例太有迷惑性了,但其实我们画图,画 n ( n ≥ 4 ) n(n\ge 4) n(n≥4) 个圆的时候,显然达不到 2 n 2^n 2n 的区域(或许画不出准确的)。
或许我们会想会不会是组合数 ∑ i = 1 n C n i = 2 n \sum_{i=1}^n C_n^i =2^n ∑i=1nCni=2n 即一个圆,两个圆相交,三个相交,四个相交,这样的排列数,但是我们画图很显然,不可能达到这样的规模,我们可以举例:
想一下如果当前有四个圆,并且相交于一个区域,新增加进来的圆若想和周围四个圆相交而且仅为两两交,是不是需要在四个相交的地方添加一个圆,且该圆不会覆盖周围四个的圆,且分别与每个圆有交,其实会画出这样的图
很粗糙的图,也不想证明,但是很明显,这个半径是最小的,都无法出现一个新的区域是 五个圆相交的。 即上面的方法在这种粗略的证明下是错误的。
我们可以换一种思路,想每一次最多会添加多少个区域,或者说什么情况下才会添加区域?
其实会发现其实每次添加区域是在旧圆 上与 新圆相交的两个相邻的点,才会出现新的区域,那么我们可以考虑最多可以有几个交点?
假设上一次有 n − 1 n-1 n−1 个圆,那么肯定只有 2 × ( n − 1 ) 2\times(n-1) 2×(n−1) 个交点,因为任意两个圆直接只有 交,切,离,包含 四种,其中交的交点数最多为 2 2 2.
既然知道交点数,那可不可能两两之间就形成新的区域呢?
很显然这交点必然在新圆上,那么他们在新圆上必然都紧密相邻,所以最多增加
2
×
(
n
−
1
)
2\times(n-1)
2×(n−1) 个区域。那我们就能列方程了:
f
1
=
2
f
n
=
f
n
−
1
+
2
(
n
−
1
)
f_1 = 2\\ f_n = f_{n-1} + 2(n-1)
f1=2fn=fn−1+2(n−1)
然后求通项,通项怎么求?
f
2
−
f
1
=
2
(
2
−
1
)
f
3
−
f
2
=
2
(
3
−
1
)
.
.
.
f
n
−
f
n
−
1
=
2
(
n
−
1
)
f_2 - f_1= 2(2-1)\\ f_3 - f_2 = 2(3-1)\\ ...\\ f_n - f_{n-1} = 2(n-1)
f2−f1=2(2−1)f3−f2=2(3−1)...fn−fn−1=2(n−1)
然后每一项相加后移项就可以得到
f
n
=
n
2
−
n
+
2
f_n = n^2 -n +2
fn=n2−n+2
K-暴食之史莱姆_河南萌新联赛2024第(三)场:河南大学 (nowcoder.com)
这题我刚刚开始一直看错题,他可以吃掉 ≤ \le ≤ 他体积的。我一直看成 < < < ,想半天了,大家可以想一下如果 < < < 怎么写,我反正没想到。
既然是 ≤ \le ≤ 那么其实就对于当前 i i i 点只要维护从 1 → i 1\rightarrow i 1→i 递增 和 i → n i\rightarrow n i→n 递减的最大序列即可。这两个之间显然互不影响,我们就可以去分别维护。
对于维护 1 → i 1 \rightarrow i 1→i ,因为要递增,每一个数仅和前面一个数的取值有关系,所以我们很容易想到维护一个栈,然后看栈顶(即前一个元素) 是否大于自身,大于说明我们吃不掉,就把他丢掉,看栈下面一个。然后如果可以就转移,即在前一个 j j j 的基础上 + 1 +1 +1 。
维护 i → n i\rightarrow n i→n 的递减显然可以用上述方法来实现。 然后两者相加即可。
时间复杂度: O ( n ) O(n) O(n)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
signed main (){
std::ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n;
cin>>n;
vector<int> a(n+1);
stack<int> s;
vector<int> pre(n+1),pos(n+1);
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
while(!s.empty() && a[s.top()] > a[i] )
s.pop();
if(!s.empty())
{
pre[i] = pre[s.top()] +1;
//cout<<i<<' '<<s.top()<<endl;
}else
pre[i] = 0;
s.push(i);
}
while(!s.empty())
s.pop();
for(int i=n;i>=1;i--)
{
while(!s.empty() && a[s.top()] > a[i] )
s.pop();
if(!s.empty())
pos[i] = pos[s.top()] +1;
else
pos[i] = 0;
s.push(i);
}
for(int i=1;i<=n;i++)
{
cout<<pre[i]+pos[i]<<' ';
}
cout<<endl;
}
A-圆周率日挑战_河南萌新联赛2024第(三)场:河南大学 (nowcoder.com)
显然是高精度题目 or python 题目,因为正常的值域在 1 0 6 10^6 106 内会有很小的误差,但是大于他或者小数位过多,都会造成 精度误差过大。
然后高精度大多数都是在整数域内进行,所以我们需要把圆周率整数一下,即 × 1 0 100 \times 10^{100} ×10100 即可。
然后对于除法我们肯定更乐意于加法,所以我们可以把 π = P 2 4 A → π × 4 A = P 2 \pi = \frac{P^2}{4A} \rightarrow \pi \times 4A = P^2 π=4AP2→π×4A=P2 然后算差值最小即可。
复杂度为 O ( n × ( 100 × 1700 + 170000 ) ) O( n\times(100\times 1700 + 170000 )) O(n×(100×1700+170000)) 前面为乘法的复杂度,后面为减数的复杂度。
显然不行,也懒得优化了,就丢一点精度吧。直接 P 2 4 A \frac {P^2}{4A} 4AP2 拿去做减法算了。
其实维护 100 100 100 位的精度也是没有必要的,不妨想一下除法最大的小数位为多少?
1 1 0 17 \frac{1}{10^{17}} 10171 所以我们仅需维护多一倍保险 40 位即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
string pi = "31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679";
//vector<pair<string,char>
// a-b 都是从小到大 最低位在 0 sub 返回是 abs值
// 初始 a > b 末尾都补 $10^2$ 个 0
string sub (string a,string b)
{ string ans ;
if(a.size() < b.size())
swap(a,b);
else if(a.size() == b.size())
{
int len = a.size();
for(int i=len-1;i>=0;i--)
{
if(a[i] > b[i])
{
break;
}
else if(a[i]==b[i])
;
else
{
swap(a,b);
break;
}
}
}
int lenb = b.size();
for(int i=0;i<lenb;i++)
{ int A = a[i] - '0';
int B = b[i] - '0';
if(A - B <0)
{
a[i+1] -=1;
// 要注意不能直接 + 因为可能爆char 直接被这个东西卡过
// -1 不会
ans.push_back((char)(A-B +10 + '0'));
}
else
ans.push_back((char)(A-B + '0'));
}
int lena = a.size();
// 最后一位要判断一下是否还存在
for(int i=lenb;i<lena;i++)
{
if(a[i] <'0')
{
a[i+1] -=1;
ans.push_back((char)(a[i]+10));
}
else
ans.push_back((char)(a[i]));
}
while(--lena)
{
if(ans[lena] == '0')
ans.pop_back();
else
break;
}
return ans;
}
int cmp(string a,string b) // a>b:1 a<b:0 a==b :2
{
if(a.size() < b.size())
return 0;
else if(a.size() == b.size())
{
int len = a.size();
for(int i=len-1;i>=0;i--)
{
if(a[i] > b[i])
return 1;
else if(a[i]==b[i])
;
else
return 0;
}
return 2;
}
return 1;
}
signed main (){
std::ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
for(int i=0;i<60;i++)
pi.pop_back();
// reverse 使得数位低的在数组低的
reverse(pi.begin(),pi.end());
// 处理数据 要 ×10^{40} 或者先除法,然后余数慢慢加入
int n;
cin>>n;
string mi = "00000000000000000000000000000000000000000000000000000000000000000001";
int ansa =0,ansb=0;
for(int i=1;i<=n;i++)
{
int p,q;
cin>>p>>q;
string a; //
a = to_string (p/q) ;
int res = p%q;
for(int j=0;j<40;j++)
{
res = res*10;
a.push_back((char)(res/q + '0'));
res %=q;
}
//cout<<a.size()<<endl;
reverse(a.begin(),a.end());
string c = sub(a,pi);
//cout<<c.size()<<endl;
int now = cmp(mi,c);
// 要记得判断等于情况
if(now == 2 && ansa > p)
{
ansa = p;
ansb = q;
mi = c;
}
else if(now==1)
{
ansa = p;
ansb = q;
mi = c;
}
}
cout<<ansa<<' '<<ansb<<endl;
}
D-开心消消乐(Right Version)_河南萌新联赛2024第(三)场:河南大学 (nowcoder.com)
由题意可以知道是从右往左的,即左边的操作不会影响右边的,那么左边肯定要消去后,才能往右边走,那么我们左边既然要消去,肯定要异或 自身,这个自身,可能前面一个数也是自身,那样就不会增加操作数,否则增加,但是 0 0 0 的时候要特判一下就好
#include<bits/stdc++.h>
using namespace std;
#define ll long long
signed main (){
std::ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int now = 0;
int ans = 0;
for(int i=1;i<=n;i++)
{
if(a[i] == now)
{
;
}
else
{ if(a[i] == 0)
;
else
ans ++;
now = a[i];
}
}
cout<<ans<<endl;
}
M-推箱子_河南萌新联赛2024第(三)场:河南大学 (nowcoder.com)
暴力搜索,然后记录状态就号了,因为每个点就会被搜索一次所以复杂度 O ( 3 0 4 ) O(30^4) O(304)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 33;
int grid[N][N];
int dis[N][N][N][N];
pair<int,int> dir[] = {
{1,0},{-1,0},{0,1},{0,-1}
};
int vis[N][N][N][N];
signed main (){
std::ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int x1,x2,x3,y1,y2,y3;
cin>>x1>>y1>>x2>>y2>>x3>>y3;
int m;
cin>>m;
while(m--)
{
int x,y;
cin>>x>>y;
grid[x][y] = 1;
}
queue<array<int,4> > q;
q.push({x1,y1,x3,y3});
auto jud=[&] (int x,int y)
{
if(x<1 || y<1 || x>30 || y>30 || grid[x][y])
return true;
else
return false ;
};
auto ner=[&] (int px,int py,int bx,int by)
{
if(px == bx && by == py)
return true;
else
return false ;
};
memset(dis,0x3f,sizeof dis);
dis[x1][y1][x3][y3] = 0;
while(!q.empty())
{
auto [px,py,bx,by] = q.front();
q.pop();
// if(px == 5 && py ==3 )
// cout<<"case1"<<' '<<bx<<' '<<by<<endl;
//cout<<px<<' '<<py<<' '<<bx<<' '<<by<<endl;
if(bx == x2 && by == y2)
{
cout<<dis[px][py][bx][by]<<endl;
return 0;
}
if(vis[px][py][bx][by])
continue ;
vis[px][py][bx][by] = 1;
for(auto [dx,dy] : dir)
{
if(jud(px+dx,py+dy))
{
continue ;
}
// if(px == 6 && py == 5)
// { cout<<"case"<<endl;
// cout<<dx<<' '<<dy<<endl;
// cout<<bx<<' '<<by<<endl;
//
// cout<<ner(px+dx,py+dy,bx,by)<<endl;
//
// }
// if(px == 4 && py == 3 )
// cout<<"case2:"<<px+dx<<' '<<py+dy<<' '<<bx<<' '<<by<<' '<<ner(px+dx,py+dy,bx,by)<<endl;
if(ner(px+dx,py+dy,bx,by))
{
if(jud(bx+dx,by+dy))
{
continue ;
}
else if(dis[px+dx][py+dy][bx+dx][by+dy] > dis[px][py][bx][by] + 1)
{
dis[px+dx][py+dy][bx+dx][by+dy] = dis[px][py][bx][by] + 1;
q.push({px+dx,py+dy,bx+dx,by+dy});
}
}
else if(dis[px+dx][py+dy][bx][by] > dis[px][py][bx][by] + 1)
{
// if(px == 4 && py == 3 )
// cout<<"case1"<<' '<<bx<<' '<<by<<' '<<dx<<' '<<dy<<endl;
//cout<<px+dx<<' '<<py+dy<<' '<<bx<<' '<<by<<endl;
dis[px+dx][py+dy][bx][by] = dis[px][py][bx][by] + 1;
q.push({px+dx,py+dy,bx,by});
}
}
}
cout<<-1<<endl;
}