前言:谁和我说这次题会简单一些的???
我就信了出题人的鬼话,谁跟我说这次题目会稍微简单一些的?真是实力劝退,这次5000多人没一个ak的,我真是服了。
A、欧几里得
这个题的定位应该是签到题,贼简单,就是个斐波那契数列的递推,没啥说的。
import java.util.Arrays;import java.util.*;class q {private long[] l=new long[83];private long a(int n){if(l[n]==0){l[n]=a(n-1)+a(n-2);}return l[n];}q() {Arrays.fill(l,0);l[0]=1;l[1]=1;l[2]=2;l[3]=3;l[4]=5;Scanner scanner=new Scanner(System.in);int T=scanner.nextInt();while(T--!=0){int s=scanner.nextInt();if(s==0){System.out.println(1);continue;}if(s==1){System.out.println(3);continue;}System.out.println(a(s+2));}}}public class Main{public static void main(String[] args) {new q();}}
B、括号序列
这个题我在刷leetcode的时候遇到过原题……..和题干一模一样。
考的就是个栈,相同就出栈,不同就入栈,最后看有没有剩下的。
import java.util.*;class q {private boolean isValid(String s) {if (s.length() == 0)return true;if (s.length() % 2 == 1)return false;Stack<Character> q = new Stack<>();for (char e : s.toCharArray()) {if (q.size() == 0){if (e == ']' || e == '}' || e == ')')return false;q.push(e);} else {char www = q.lastElement();if (www == '{' && (e == ']' || e == ')'))return false;if (www == '(' && (e == '}' || e == ']'))return false;if (www == '[' && (e == '}' || e == ')'))return false;if (www == '{' && e == '}')q.pop();else if (www == '[' && e == ']')q.pop();else if (www == '(' && e == ')')q.pop();else q.push(e);}}return q.size() == 0;}q() {String k = new Scanner(System.in).next();if(k.equals("i"))System.out.print("Yes");else {if (isValid(k)) System.out.print("Yes");else System.out.print("No");}}}public class Main {public static void main(String[] args) {new q();}}
C、子段乘积
这道题一上场信心满满,感觉就是个先乘再除,后来发现这个得考虑到 之后不能直接除的问题,就没了思路,刚刚查找了相关的数论知识,了解到这个题涉及到了卢卡斯定理这个知识,这个题就是:知道这个卢卡斯定理的就做得出来,不知道的就做不出来。本质是个求乘法逆元的过程。然后就是走模板了。感觉这个题和之前遇到的什么分数求模有相同的背景。啊,明白了。
import java.util.Scanner;class q{private long qpow(long a, long b, long p){long ans=1;while(b!=0){if(b%2!=0)ans=ans*a%p;a=a*a%p;b>>=1;}return ans;}private long inv(long a, long p){return qpow(a,p-2,p);}q(){Scanner cin=new Scanner(System.in);int n=cin.nextInt();int k=cin.nextInt();long[] a=new long[n];long ans=0,S=1;long mod=998244353;long num=0;for(int i=0;i<n;i++){a[i]=cin.nextLong();if(a[i]==0){S=1;num=0;}else{S=S*a[i]%mod;num+=1;if(num>k){S=S*inv(a[i-k],mod)%mod;num-=1;}if(num==k)ans=Long.max(ans,S%mod);}}System.out.println(ans);}}public class Main { public static void main(String[] args) {new q();}}
回头得整理到数论的专题里。
D、子段异或
因为昨天刚刚细细品味了数位DP,导致这个题我的第一反应就是数位DP。数位DP倒不是不能做,就是在自找麻烦,数位dp本身就是把所有的情况推一遍,导致了这道题复杂度 。然后刚刚在看别人的解答的时候,发现了一个比较有趣的思路,感觉很棒,利用了累乘的特性,这里贴出来。
import java.util.*;class q{q(){Scanner sc=new Scanner(System.in);long a[]=new long[200005];Map<Long,Long> map=new HashMap<Long,Long>();a[0]=0;int n=sc.nextInt();for(int i=1;i<=n;i++) {int x=sc.nextInt();a[i]=a[i-1]^x;}long ans=0;map.put(0L,1L);for(int i=1;i<=n;i++) {if(map.containsKey(a[i])) {ans+=map.get(a[i]);map.put(a[i],map.get(a[i])+1);}else map.put(a[i],1L);}System.out.println(ans);}}public class Main { public static void main(String[] args) {new q();}}
E、最小表达式
这个题…..有点玄妙,这么说,他居然特意去用数据卡了Java的大数。
这个题的本意不难,就是个流程题,具体步骤为:
没了,剩下的就是码代码了。
#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>using namespace std;char ch[1000000],ans[1000000];int num[11];int main(){scanf("%s",ch);int n=strlen(ch);int cnt=1;for(int i=0;i<n;i++){if(ch[i]=='+')cnt++;else num[ch[i]-'0']++;}int k=0,temp=0,cnt1=0;for(int i=9;i>=1;i--){for(int j=1;j<=num[i];j++){temp+=i;k++;if(k%cnt==0){ans[cnt1++]=temp%10+'0';temp/=10;}}}while(temp){ans[cnt1++]=temp%10+'0';temp/=10;}for(int i=cnt1-1;i>=0;i--)printf("%c",ans[i]);printf("\n");return 0;}
F、树上博弈
啊,当时没看这个题,现在说说对这个的想法,由题意,因为每一步都必须要走,所以应该想办法让两者之间的距离(最短路径长度)为奇数,这样,总会有一步起,两者间的距离会变成1,然后只要牛牛走一步,牛妹就必须后退一步(突然羡慕牛牛有可爱的妹子),直到牛妹被逼到死胡同。然后的就是算出来有多少种取样方式,可以使两者之间的距离为奇数。预计时间复杂度。问题是怎么去举可以令计算次数尽量的小。感觉可以用记录的方法,即:记录这个节点到树顶点的距离,然后进行个分治,即通过距离来算。
刚刚看了看别人的代码,大部分都是先数据初始化,把父子节点的关系先整明白,然后在去深搜来确定位置关系,然后用 直接把结果算出来。等等,看到了个直接用结构体,然后直接记录深度的,啊,这个才是正常的想法。
#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;typedef long long LL;template <class T> inline T rd(){T x = 0;ll f = 1; char c = getchar();while(c > '9' || c < '0') f = c == '-' ? -1 : 1, c = getchar();while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();return x * f;}#define rdi rd<int>#define N 1000005struct node{int fa;int dep;}a[N];int main() {int n = rdi();for (int i = 2 ; i <= n ; i++ ) {a[i].fa = rdi();a[i].dep = a[a[i].fa].dep + 1;}LL cnt1 = 0, cnt2 = 0;for (int i = 1 ; i <= n ; i++ ) {if (a[i].dep % 2 == 0) cnt2++;else cnt1++;}LL ans = cnt1 * (cnt1 - 1) / 2 + cnt2 * (cnt2 - 1) / 2;cout << ans * 2 << '\n';}
G、音乐鉴赏
坦白的说,这个题我一开始没读懂题意。然后我刚刚看了看别人的代码是个什么意思。
如果随机占比为 ,一个人分数为
,那么他优秀的概率为
。
这个概率可以这么计算:首先把分数减90,大于0就优秀,那么就变成,其中y是一个随机的0到90之间的数字。
,这个概率就是上面所写的概率。
,解方程可知答案为。
import java.util.*;public class Main{static long MOD = 998244353;public static void main(String[] args){Scanner in = new Scanner(System.in);int n = in.nextInt();int num = 0;for(int i=0;i<n;i++) num += in.nextInt();double average = num*1.0 / n;double p = (average - 90)*100 / (average -81);System.out.printf("%.2f", p);System.out.println("%");}}
H、坐火车
这个题我感觉应该是采用记忆的方式,即每扫描一个车厢,就在以经过该种车厢的颜色的计数板上+1,之后每次在后边可以直接用来计算某种颜色对这节车厢的贡献。然后如果直接写代码的话会TLE,所以得进行个维护。
这个是TLE版。
import java.util.Scanner;class color{int left=0;int right=1;}class q{q(){Scanner scanner=new Scanner(System.in);int n=scanner.nextInt();color[] colors=new color[500001];int[][] train=new int[n][3];for(int i=0;i<n;i++){train[i][0]=scanner.nextInt();train[i][1]=scanner.nextInt();train[i][2]=scanner.nextInt();if(colors[train[i][0]]==null)colors[train[i][0]]=new color();else colors[train[i][0]].right++;}long sum=0;System.out.print(0);System.out.print(" ");colors[train[0][0]].right--;colors[train[0][0]].left++;for(int i=1;i<n-1;i++){colors[train[i][0]].right--;for(int j=train[i][1];j<=train[i][2];j++){if(colors[j]!=null)sum+=(colors[j].left*colors[j].right);}System.out.print(sum);System.out.print(" ");sum=0;colors[train[i][0]].left++;}System.out.print(0);System.out.print(" ");}}public class Main { public static void main(String[] args) {new q(); }}
正常版
import java.util.Scanner;class color{int left=0;int right=1;}class q{private int N = 500050;private long[] sz=new long[N];private void add(int p, int x){while(p<N){sz[p]+=x;p+=p&-p;}}private long query(int p){long ret = 0;while(p!=0){ret+=sz[p];p-=p&-p;}return ret;}q(){Scanner scanner=new Scanner(System.in);int n=scanner.nextInt();color[] colors=new color[500001];int[][] train=new int[n][3];for(int i=0;i<n;i++){train[i][0]=scanner.nextInt();train[i][1]=scanner.nextInt();train[i][2]=scanner.nextInt();if(colors[train[i][0]]==null)colors[train[i][0]]=new color();else colors[train[i][0]].right++;}for(int i=0;i<n;i++){colors[train[i][0]].right-=1;add(train[i][0],-colors[train[i][0]].left);System.out.print(query(train[i][2])-query(train[i][1]-1));System.out.print(" ");colors[train[i][0]].left+=1;add(train[i][0],colors[train[i][0]].right);}}}public class Main { public static void main(String[] args) {new q(); }}
I、匹配星星
这个题有点迷,看解析,意思是采用贪心,
- 如果
,查询比他X坐标小的Y坐标最大的
的点,进行配对,如果配对成功则将那个点都从候选点中排除。
- 如果
,将该点加入候选点。
证明
假设最优方案中排序后的第 1 个没有按贪心策略匹配的点
,在设
在
中它能匹配的
最大的点为
,如果
被点
匹配了,有两种情况:
- 原先
没有和任何匹配,则直接去掉
的匹配,将
和
匹配。
- 原先
和
匹配,则将
改成和
匹配,将
和
匹配,由于
, 这样的匹配一定是成立的。并且修改后的匹配数不会变少,因此按照该贪心策略可以得到最优解。
#include <set>#include <vector>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;struct P{int a,b,c;bool operator < (const P &rhs) const{if(a == rhs.a)return c>rhs.c;return a<rhs.a;}}alp[300030];int n;int main() {cin>>n;for(int i=0;i<n;i++) cin>>alp[i].a>>alp[i].b>>alp[i].c;sort(alp,alp+n);multiset<int> pool;multiset<int>::iterator it;int ans = 0;for(int i=0;i<n;i++){if(alp[i].c){it = pool.lower_bound(alp[i].b);if(it!=pool.begin()){--it;pool.erase(it);ans+=1;}}else{pool.insert(alp[i].b);}}cout<<ans<<endl;return 0;}
