目录
A、签到时刻
import java.util.*;
import java.io.*;
public class Main {
static class FastReader{
BufferedReader br;
StringTokenizer st;
String tmp;
public FastReader() {
br=new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while(st==null||!st.hasMoreElements()) {
try {
st=new StringTokenizer(br.readLine());
}catch(IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong(){return Long.parseLong(next());}
String nextLine() {
String str="";
try {
str=br.readLine();
}catch(IOException e) {
e.printStackTrace();
}
return str;
}
boolean hasNext(){
if(st!=null&&st.hasMoreTokens())return true;
try {
tmp=br.readLine();
st=new StringTokenizer(tmp);
}catch(IOException e) {
return false;
}
return true;
}
}
static PrintWriter out=new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.out)));
static FastReader cin=new FastReader();
public static void main(String[] args) {
int t=cin.nextInt();
while(t-->0) {
int n=cin.nextInt();
int cnt1=0,cnt2=0;
while(n-->0) {
String s=cin.next();
String ss[]=s.split(":");
if(Integer.parseInt(ss[0])<8||(Integer.parseInt(ss[0])==8&&Integer.parseInt(ss[1])==0))continue;
if(Integer.parseInt(ss[0])==8&&Integer.parseInt(ss[1])<=5&&Integer.parseInt(ss[1])>0)cnt1++;
else cnt2++;
}
out.println(cnt1+" "+cnt2);
}
out.flush();
}
}
B、牛牛的身高
思路:通过读题我们可以知道,当某个位数>=5时就可以进位,而此时进位后面的所有数都要射去,所以我们只需要从最低位到最高位进行遍历,判断是否有进位并记录即可。
import java.util.*;
import java.io.*;
public class Main {
static class FastReader{
BufferedReader br;
StringTokenizer st;
String tmp;
public FastReader() {
br=new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while(st==null||!st.hasMoreElements()) {
try {
st=new StringTokenizer(br.readLine());
}catch(IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong(){return Long.parseLong(next());}
String nextLine() {
String str="";
try {
str=br.readLine();
}catch(IOException e) {
e.printStackTrace();
}
return str;
}
boolean hasNext(){
if(st!=null&&st.hasMoreTokens())return true;
try {
tmp=br.readLine();
st=new StringTokenizer(tmp);
}catch(IOException e) {
return false;
}
return true;
}
}
static PrintWriter out=new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.out)));
static FastReader cin=new FastReader();
public static void main(String[] args) {
int t=cin.nextInt();
while(t-->0) {
String s=cin.next();
char c[]=s.toCharArray();
int m=0,f=-1;//m用来记录在i处是否有进位,f用来记录最大进位的位置
for(int i=c.length-1;i>=0;i--) {
m+=c[i]-'0';
if(m>=5) {
f=i;
c[i]='0';
m=1;
}else {
c[i]=(char)(m+'0');
m=0;
}
}
if(m>0)out.print(m);
if(f<0)f=c.length;
for(int i=0;i<f;i++) {
out.print(c[i]);
}
for(int i=f;f>=0&&i<c.length;i++)
out.print(0);
out.println();
out.flush();
}
}
}
C、说谎的机器
思路:通过题意我们可以知道,当求机器的错误指令数最多,那么也就是求,一个取值所涵盖的正确次数最少。而且通过题意我们可以发现,每次的机器指令覆盖的都是一段区间,所以我们可以通过差分来求解,最后使用前缀和来得出每个数字被机器指令覆盖的次数,找出最小值,最后输出即可。
import java.util.*;
import java.io.*;
public class Main {
static class FastReader{
BufferedReader br;
StringTokenizer st;
String tmp;
public FastReader() {
br=new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while(st==null||!st.hasMoreElements()) {
try {
st=new StringTokenizer(br.readLine());
}catch(IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong(){return Long.parseLong(next());}
String nextLine() {
String str="";
try {
str=br.readLine();
}catch(IOException e) {
e.printStackTrace();
}
return str;
}
boolean hasNext(){
if(st!=null&&st.hasMoreTokens())return true;
try {
tmp=br.readLine();
st=new StringTokenizer(tmp);
}catch(IOException e) {
return false;
}
return true;
}
}
static PrintWriter out=new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.out)));
static FastReader cin=new FastReader();
public static void main(String[] args) {
int n=cin.nextInt(),m=cin.nextInt();
int a[]=new int[n+2];
for(int i=0;i<m;i++) {
int op=cin.nextInt();
if(op==1) {
int x=cin.nextInt(),y=cin.nextInt();
a[x]++;a[y+1]--;
}else if(op==2){
int x=cin.nextInt();
a[x]++;a[n+1]--;
}else {
int y=cin.nextInt();
a[1]++;a[y+1]--;
}
}
//map用来记录出现的数字的次数
HashMap<Integer,Integer> map=new HashMap<>();
int min=Integer.MAX_VALUE;
for(int i=1;i<=n;i++) {
a[i]+=a[i-1];
min=Math.min(min,a[i]);
map.put(a[i],map.getOrDefault(a[i],0)+1);
}
out.println((m-min)+" "+map.get(min));
out.flush();
}
}
D、环上食虫
思路:分析可得蛋糕是圆圈排列,要求在能够吃饱的情况下,他吃到蛋糕中奶油含量最高的那一个最低会是多少,我们需要模拟出所有得满足它能吃饱得区间,然后求在这些区间中出现的蛋糕中奶油含量最高的那一个的最小值。
import java.util.*;
import java.io.*;
public class Main {
static class FastReader{
BufferedReader br;
StringTokenizer st;
String tmp;
public FastReader() {
br=new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while(st==null||!st.hasMoreElements()) {
try {
st=new StringTokenizer(br.readLine());
}catch(IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong(){return Long.parseLong(next());}
String nextLine() {
String str="";
try {
str=br.readLine();
}catch(IOException e) {
e.printStackTrace();
}
return str;
}
boolean hasNext(){
if(st!=null&&st.hasMoreTokens())return true;
try {
tmp=br.readLine();
st=new StringTokenizer(tmp);
}catch(IOException e) {
return false;
}
return true;
}
}
static PrintWriter out=new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.out)));
static FastReader cin=new FastReader();
public static void main(String[] args) {
int n=cin.nextInt(),s=cin.nextInt();
long sum=0;
long a[]=new long[n*2+1];//记录蛋糕的饱腹值
long b[]=new long[n*2+1];//记录蛋糕的奶油含量
long f[]=new long[n*2+1];//记录蛋糕的饱腹值的前缀和
for(int i=1;i<=n;i++) {
a[i]=cin.nextLong();
a[i+n]=a[i];
f[i]=f[i-1]+a[i];
}
for(int i=1;i<=n;i++) {
b[i]=cin.nextLong();
b[i+n]=b[i];
}
if(f[n]<s)out.println(-1);
else {
//用来记录某一段取值中各个奶油含量值及个数
HashMap<Long,Integer> map=new HashMap<>();
long max=-1,ans=-1;
int i=1;
//找出第一个>=s的位置
for(;i<=n;i++) {
max=Math.max(max,b[i]);
map.put(b[i],map.getOrDefault(b[i],0)+1);
if(f[i]>=s)break;
}
ans=max;
int j=i+1;//用来记录右端点移动的位置
long sf=f[i];//当前区间的饱腹值总和
i=1;
while(i<=n) {
//左端每次点向右移动一位,寻找下一个满足题意的区间
while(i<=n&&sf>=s) {
ans=Math.min(ans,max);
sf-=a[i];
map.put(b[i],map.getOrDefault(b[i],0)-1);
//删除个数为零的奶油值
if(map.getOrDefault(b[i],0)==0)map.remove(b[i]);
//如果移动的左端点刚好的该区间的唯一一个最大奶油含量,重新查找该段区间中最大的奶油含量
if(max==b[i]&&!map.containsKey(b[i])) {
max=0;
for(long x:map.keySet()) {
max=Math.max(max,x);
}
}
i++;
}
//找寻下一个满足题意得一段区间
while(j<2*n&&sf<s) {
sf+=a[j];
map.put(b[j],map.getOrDefault(b[j],0)+1);
max=Math.max(max,b[j]);
j++;
}
//区间最多只包含n个蛋糕
if(j-i>n)break;
}
out.println(ans);
}
out.flush();
}
}
E、分组求对数和
思路:分析可知,找出不同组的两个数字和大于>=k,所以我们可以用一个数组将所有的s都存起来,用一个二维数组存第i个小朋友手中的数字,并将其全部进行排序;然后遍历每一个小朋友手中的数字,得到m=k-x;通过二分查找找出小朋友手中大于m的数量和总体大于m的数量,最后相减即可能与该数字组合满足条件的其他小朋友手中的数字的数量。又由于每一对数字被算了两次,所有最后得到的答案总和/2;
import java.util.*;
import java.io.*;
public class Main {
static class FastReader{
BufferedReader br;
StringTokenizer st;
String tmp;
public FastReader() {
br=new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while(st==null||!st.hasMoreElements()) {
try {
st=new StringTokenizer(br.readLine());
}catch(IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong(){return Long.parseLong(next());}
String nextLine() {
String str="";
try {
str=br.readLine();
}catch(IOException e) {
e.printStackTrace();
}
return str;
}
boolean hasNext(){
if(st!=null&&st.hasMoreTokens())return true;
try {
tmp=br.readLine();
st=new StringTokenizer(tmp);
}catch(IOException e) {
return false;
}
return true;
}
}
static PrintWriter out=new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.out)));
static FastReader cin=new FastReader();
public static void main(String[] args) {
int n=cin.nextInt(),k=cin.nextInt();
int mod=998244353;
Vector<Integer> a[]=new Vector[n];
Vector<Integer> b=new Vector<>();
long ans=0;
for(int i=0;i<n;i++) {
a[i]=new Vector<>();
int s=cin.nextInt();
for(int j=0;j<s;j++) {
int x=cin.nextInt();
a[i].add(x);
b.add(x);
}
Collections.sort(a[i]);
}
Collections.sort(b);
for(int i=0;i<n;i++) {
for(int j=0;j<a[i].size();j++) {
int m=k-a[i].get(j);
long num1=ms(m,a[i]);
long num2=ms(m,b);
// out.println(num1+" "+num2);
ans+=num2-num1;
}
}
out.println((ans/2)%mod);
out.flush();
}
private static long ms(int m, Vector<Integer> b) {
// TODO Auto-generated method stub
int l=0,r=b.size()-1;
while(l<r) {
int mid=(l+r)>>1;
if(b.get(mid)<m)l=mid+1;
else r=mid;
}
if(l==r&&b.get(r)<m)return 0;
return b.size()-r;
}
}
F、骑士战胜魔王
思路:题意:1、找出骑士技能之和>=m的方案数;
2、当骑士能量消耗之和不同时方案才不同;
通过分析,将能量消耗固定,找出在某个能量消耗下最大攻击值(最大攻击值能满足条件,就不同管比较小的了),那么,就可以确保能找出总的方案数;
import java.util.*;
import java.io.*;
public class Main {
static class FastReader{
BufferedReader br;
StringTokenizer st;
String tmp;
public FastReader() {
br=new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while(st==null||!st.hasMoreElements()) {
try {
st=new StringTokenizer(br.readLine());
}catch(IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong(){return Long.parseLong(next());}
String nextLine() {
String str="";
try {
str=br.readLine();
}catch(IOException e) {
e.printStackTrace();
}
return str;
}
boolean hasNext(){
if(st!=null&&st.hasMoreTokens())return true;
try {
tmp=br.readLine();
st=new StringTokenizer(tmp);
}catch(IOException e) {
return false;
}
return true;
}
}
static PrintWriter out=new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.out)));
static FastReader cin=new FastReader();
public static void main(String[] args) {
int n=cin.nextInt(),m=cin.nextInt();
int mod=998244353;
long f[][]=new long[n+1][m+1];//代表1-i个骑士所有技能中,攻击值为j的个数
f[0][0]=1;
for(int i=1;i<=n;i++) {
int s=cin.nextInt();
int sum=0;//该骑士使用所有技能所消耗的总值
int a[]=new int[s+1];//攻击值
int b[]=new int[s+1];//消耗值
for(int j=1;j<=s;j++)a[j]=cin.nextInt();
for(int j=1;j<=s;j++) {
b[j]=cin.nextInt();
sum+=b[j];
}
long g[]=new long[sum+1];//用来记录消耗值为i的情况下的最大攻击值
Arrays.fill(g,Integer.MIN_VALUE);
g[0]=0;//初始化
//01背包问题求解在固定的消耗值的情况下最大攻击值
for(int j=1;j<=s;j++) {
for(int k=sum;k>=b[j];k--) {
g[k]=Math.max(g[k],g[k-b[j]]+a[j]);
}
}
//遍历攻击值,进行累加
for(int j=0;j<=sum;j++) {
if(g[j]<0)continue;
for(int k=0;k<=m;k++) {
//当k+g[j]>=m说明满足条件
int x=(int)Math.min(m,k+g[j]);
f[i][x]=(f[i][x]+f[i-1][k])%mod;
}
}
}
out.println(f[n][m]);
out.flush();
}
}