B~F题解
按照题目模拟就好了,时间复杂度O(n)
import java.util.*;
public class Main{
static int mod=(int)1e9+7;
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),a[]=new int[n],cur=0;
for(int i=0;i<n;i++){
a[i]=sc.nextInt();
}
long ans=0;
for(char c:sc.next().toCharArray()){
cur=c=='L'?Math.max(0,cur-1):Math.min(cur+1,n-1);
ans+=a[cur];
}
System.out.println(ans%mod);
}
}
我不是数学家,不会证明为什么这么做,瞎吉巴试就行了:先排序,偶数数组的话,首尾依次向中间靠拢相乘,否则空出最大的数字,剩下的首尾依次向中间靠拢相乘,时间复杂度O(nlogn)
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
long a[]=new long[n];
for(int i=0;i<n;i++){
a[i]=sc.nextInt();
}
Arrays.sort(a);
long max=-(long)1e18,min=-max;
if(n%2==1){
max=min=a[n-1];
}
for(int i=0,j=n-1-n%2;i<j;i++,j--){
max=Math.max(max,a[i]*a[j]);
min=Math.min(min,a[i]*a[j]);
}
System.out.println(max-min);
}
}
首先排除n为奇数的情况;;n为偶数的时候,需要看一条边连接的两个连通块,假如都是偶数个点的话,这个边就能删除,假如暴力删边再验证是平方度咋读会超时,因袭可以利用由底向上的递归来实现,记录每个节点子树方向的总点数情况,是偶数的可以删,这样只需一次遍历,时间复杂度O(n)
import java.util.*;
public class Main{
static int ans=0;
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
if(n%2==1){
System.out.println("-1");
return;
}
List<Integer> path[]=new List[n+5];
for(int i=1;i<=n;i++){
path[i]=new ArrayList<>();
}
for(int i=0;i<n-1;i++){
int u=sc.nextInt(),v=sc.nextInt();
path[u].add(v);
path[v].add(u);
}
find(1,path,new int[n+5],new boolean[n+5]);
System.out.println(ans);
}
static void find(int k,List<Integer> path[],int count[],boolean has[]){
has[k]=true;
count[k]=1;
for(int a:path[k]){
if(!has[a]){
find(a,path,count,has);
count[k]^=count[a];
if(count[a]==0){
ans++;
}
}
}
}
}
比较裸的前缀和+贡献量的思路,每个数字有选和不选两种情况,考虑到逆元的计算,本代码核心算法时间复杂度为O(n*klog(mod))
,本题中mod==1e9+7
import java.util.*;
public class Main{
static int mod=(int)1e9+7;
static long fac[]=new long[1005];
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
fac[0]=1;
for(int i=1;i<=1000;i++){
fac[i]=fac[i-1]*i%mod;
}
int n=sc.nextInt(),k=sc.nextInt();
String s=sc.next();
long ans[][]=new long[n+1][k+1];
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
ans[i][j]=(ans[i-1][j]+ans[i-1][j-1]+comb(i-1,j-1)*(s.charAt(i-1)-'0')*pow(10,k-j))%mod;
}
}
System.out.println(ans[n][k]);
}
static long comb(int a,int b){
return a<b?0:fac[a]*pow(fac[b],mod-2)%mod*pow(fac[a-b],mod-2)%mod;
}
static long pow(long a,int b){
long ans=1;
while(b!=0){
if(b%2==1){
ans=ans*a%mod;
}
a=a*a%mod;
b>>=1;
}
return ans;
}
}
思路:状态(i,j)
的定义为从有i个2和j个3,(其中i的最大值为count2,j的最大值为count3),到首次达到合法状态时好需要操作的次数期望,分类讨论各种转移,并且从大到小更新,,时间复杂度:小于O((logX)^2*log(mod))
,本题中mod==1e9+7
import java.util.*;
public class Main{
static int mod=(int)1e9+7;
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
long x=sc.nextLong();
int count2=0,count3=0;
while(x%2==0){
x/=2;
count2++;
}
while(x%3==0){
x/=3;
count3++;
}
if(x!=1){
System.out.println("-1");
return;
}
long ans[][]=new long[count2+1][count3+1];
for(int i=count2;i>=0;i--){
for(int j=count3;j>=0;j--){
if(i==count2&&j==count3){
continue;
}
if(i==count2){
ans[i][j]=(ans[i][j+1]+3)%mod;
}
else if(j==count3){
ans[i][j]=(ans[i+1][j]+3)%mod;
}
else{
ans[i][j]=(ans[i+1][j]+ans[i][j+1]+3)*pow(2,mod-2)%mod;
}
}
}
System.out.println(ans[0][0]);
}
static long pow(long a,int b){
long ans=1;
while(b!=0){
if(b%2==1){
ans=ans*a%mod;
}
b>>=1;
a=a*a%mod;
}
return ans;
}
}