菜鸡的补题之路
这场好菜呀,呗两个队友带了三题,可能是太久没有刷题了吧,最近一直在复习和实训。
赛后补了几题,写下题解,之后继续补,继续写。
首先看到J题两分钟有人就a了,就跑去看了,然后就是一个签到,丢给大一的大佬写了个py过了,赛后自己用__int128 写了下。
#include <bits/stdc++.h>usingnamespacestd;typedeflonglongll;intmain(){ll a,b,x,y;while(cin>>x>>a>>y>>b){if((__int128)x*b < (__int128)y*a) cout<<"<"<<endl;elseif((__int128)x*b > (__int128)y*a) cout<<">"<<endl;elsecout<<"="<<endl;}return0;}
然后是F题,还是丢人呀,不断的试,终于试出来了,面积的22倍,但是如果证明还没看懂,看懂了再补。
还有一种方法是叉姐直播时说的,撒点,比赛的时候怎么就没想到呢。
然后是a题。
题意就是给你两个数组,问两个数组的最长前缀是多少时满足,两个数组前缀在任意区间内最小值的位置相同。
比赛时想了几个方法,都有反例,然后最合理的就是找当前位置的值和上一个比上升还是下降,如果两个数组的单调性相反就不成立,或者是两个都同时下降就要比较比当前值小的一个树的位置。但是没想起单调栈,就一直没出,2h后,然后学弟就想暴力n方莽一下,就™莽过了。。。当时就自闭了(没道理啊,凭什么呀,那我不是白痴吗。。。
赛后用了单调栈就过了,题解说的笛卡尔树大概去了解了一下,大概就是这个意思。
然后贴两份代码,一份是学弟的暴力,一份是单调栈。
#include <iostream>#include <stdio.h>usingnamespacestd;intn,a[100010],b[100010];intmain(){while(~scanf("%d",&n)){for(inti=1;i<=n;i++) scanf("%d",&a[i]);for(inti=1;i<=n;i++) scanf("%d",&b[i]);intans=n;for(inti=1;i<=n;i++){intflag=1;for(intj=i-1;j>0;j--){if(a[j]>a[i]&&b[j]<b[i]||a[j]<a[i]&&b[j]>b[i]){flag=0;break;}elseif(a[j]<a[i]&&b[j]<b[i]) break;}if(flag==0){ans=i-1;break;}}printf("%d\n",ans);}return0;}
单调栈
#include <bits/stdc++.h>usingnamespacestd;intmain(){intn,m;stack<int>a,b;intnum[100005],num1[100005];while(cin>>n){for(inti=1;i<=n;i++) cin>>num[i];for(inti=1;i<=n;i++) cin>>num1[i];while(!a.empty()) a.pop();while(!b.empty()) b.pop();a.push(1);b.push(1);intans=n;for(inti=1;i<=n;i++){intpa=0,pb=0;while(!a.empty()&&num[a.top()]>num[i]){a.pop();}if(!a.empty()) pa=a.top();a.push(i);while(!b.empty()&&num1[b.top()]>num1[i]){b.pop();}if(!b.empty()) pb=b.top();b.push(i);if(pa!=pb){ans=i-1;break;}}cout<<max(1,ans)<<endl;}return0;}
但是但是。。。竟然
学弟的暴力跑的比单调栈还快
然后是B题,赛后看着题解,慢慢推的。
推了好久啊。
总结大概是裂项,乘法变加法,然后化简,求不定积分
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e9+7; long long power_mod(long long a, long long b, long long mod) { long long ans = 1; while (b) { if (b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } int main() { int n,m; ll num[1005]; ios::sync_with_stdio(false); while(cin>>n){ for(int i=1;i<=n;i++) cin>>num[i]; ll sum=0; for(int i=1;i<=n;i++){ ll ans=2*num[i]; for(int j=1;j<=n;j++) if(i!=j) ans=(ans*(num[j]*num[j]%mod-num[i]*num[i]%mod+mod)%mod)%mod; sum=(sum+power_mod(ans,mod-2,mod))%mod; } cout<<sum<<endl; } return 0; }
E题, 感觉解法挺多的,还有大佬画线格图,推排列组合的。
但是大多数还是直接dp,我是dp的A和B的个数的。
只有当ab没够的时候,或者是ba中少a的时候将a的个数加一就行
具体实现看代码吧
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e9+7; int dp[2005][2005]; int main() { int n,m; while(cin>>n>>m){ for(int i=0;i<=n+m;i++){ for(int j=0;j<=n+m;j++){ dp[i][j]=0; } } dp[0][0]=1; for(int i=0;i<=n+m;i++){ for(int j=0;j<=n+m;j++){ if(i<n||(i-n)<min(j,m)) dp[i+1][j]=(dp[i][j]+dp[i+1][j])%mod; if(j<m||(j-m)<min(i,n)) dp[i][j+1]=(dp[i][j+1]+dp[i][j])%mod; } } /* for(int i=0;i<=n+m;i++){ for(int j=0;j<=n+m;j++){ cout<<dp[i][j]<<' '; } cout<<endl; } */ cout<<dp[n+m][n+m]<<endl; } return 0; }