【模板】逆序数,java大数,2014 Multi-University Training Contest 5,

2014 Multi-University Training Contest 5 出题人————叉姐
队内训练,感觉有点迷
1001
hdu 4911 Inversion
给一串数字,允许交换相邻的数字最多k次
找到最少的逆序数 : (i,j) 有iaj

由组合数学知识,一个数组的逆序数等于使其变成有序列(非降序)所进行得相邻元素交换的最少次数。
仔细想想,i,j,k swap(i,j) 并不会影响k的逆序数

所以这题就是 逆序数-k; 用线段树就好了
之前2016 多校补题补过逆序数,但那个题是1-n的全排列,所以没有相同的ai,这里需要离散化。这里“ 按位置插线段树“ 也很精髓

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<string.h>
#include<map>
#include<set>
using namespace std;
#define ll __int64
/*
 */
struct seg{
    int l,r;
    ll v;
}st[100005<<2];
void build(int l,int r,int id){
    int mid=(l+r)>>1;
    st[id].v=0;
    st[id].l=l;
    st[id].r=r;
    if(l==r) return;
    build(l,mid,id<<1);
    build(mid+1,r,(id<<1)+1);
}
void push_up(int id){
    st[id].v=max(st[id].v,st[id<<1].v+st[id*2+1].v);
}
void update(int p,int id){
//    printf("id=%d\n",id);
    if(st[id].l==p && st[id].r==p){
        st[id].v++;
        return;
    }
    int mid=(st[id].l+st[id].r)/2;
    if(p<=mid)
        update(p,id*2);
    else
        update(p,id*2+1);
    push_up(id);
}
ll qur(int l,int r,int rt){
    if(st[rt].l==l &&st[rt].r==r){
        return st[rt].v;
    }
    push_up(rt);
    int mid=(st[rt].l+st[rt].r)>>1;
    int ans=0;
    if(mid>=r){
        ans+=qur(l,r,rt<<1);
    }
    else if(l>mid){
        ans+=qur(l,r,(rt<<1)+1);
    }
    else{
        ans+=qur(l,mid,rt<<1);
        ans+=qur(mid+1,r,(rt<<1)+1);
    }
    return ans;
}
int a[100005];
int b[100005];
int main() {
    //freopen("1.txt","r",stdin);
    int n,k;
    while(~scanf("%d %d",&n,&k)){
        map<int,int>pos;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+n+1);
        for(int i=1;i<=n;i++){  //log的离散化,也许有更好离散化方法。
            if(!pos[b[i]])
                pos[b[i]]=i;
        }
        build(1,n,1);
        ll ans=0;
        for(int i=1;i<=n;i++){
            int p=pos[a[i]]; //离散化后的大小
            update(p,1);//+1
            ll cnt=qur(1,p,1); //前面比他小或等于的有cnt个
//            printf("cnt=%d\n",cnt);
            ans+=i-cnt;
        }
        ans-=k;
        if(ans<0) ans=0;
        printf("%I64d\n",ans);
    }

    return 0;
}

1009 Exclusive or
题意 不知, 小学弟直接把公式交给我,我打大数模板就好了,稳。
这里找了一个比较好的大数模板,因为需要使用记忆化搜索,还需要学一下map该如何使用。

import java.util.*;
import java.math.*; 
import java.io.*;
import java.util.Scanner;  

public class Main {
    public static BigInteger bigInteger0=BigInteger.valueOf(0);  
    public static BigInteger bigInteger1=BigInteger.valueOf(1);  
    public static BigInteger bigInteger2=BigInteger.valueOf(2);   
    public static BigInteger bigInteger4=BigInteger.valueOf(4);  
    public static BigInteger bigInteger6=BigInteger.valueOf(6);   

    public static HashMap<BigInteger,BigInteger> map=new HashMap<BigInteger,BigInteger>();  

    public static BigInteger dfs(BigInteger n){
        if(map.containsKey(n))  
            return map.get(n);  

        BigInteger ans=BigInteger.valueOf(0);
        BigInteger t=n.divide(bigInteger2);  
        BigInteger r=n.remainder(bigInteger2);

        BigInteger a=new BigInteger ("1");
        BigInteger b=new BigInteger ("1");
        a=dfs(t);
        b=dfs(t.subtract(bigInteger1));

        if(r.equals(bigInteger1))
            ans=( bigInteger4.multiply(a) ).add(bigInteger6.multiply(t));
        else {
             ans=bigInteger2.multiply(a);  
             ans=ans.add(bigInteger2.multiply(b));  
             ans=ans.add(bigInteger4.multiply(t));  
             ans=ans.subtract(bigInteger4);  
        }
        map.put(n, ans);  
        return ans;
    }
     public static void main(String[] args) {
         Scanner cin = new Scanner (System.in);
         BigInteger x;
         map.put(bigInteger0, bigInteger0);  
         map.put(bigInteger1,bigInteger0);  
         while(cin.hasNext())  {  
                x=cin.nextBigInteger();  
                System.out.println(dfs(x));
          }   
     }

}   

1010 Matrix multiplication
题意很简单:求两个矩阵相乘 800*800的矩阵

最让我没想到的是: 判断会比相乘的时间还要多。
以后做常数优化,记住: 稍作判断,宁愿做运算,也尽量少做判断。还有貌似a=a+b,比a+=b, 要快,(没验证过,不知真假)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<string.h>
#include<map>
#include<set>
using namespace std;
#define ll __int64
/*
把 每i行的第j个 放进 map<pair<i,j>,int >
所以 aij *bji 存在int

 */
int matr1[805][805];
int matr2[805][805];
int matr3[805][805];

int main() {
    //freopen("1.txt","r",stdin);
    int n;
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&matr1[i][j]),matr1[i][j]%=3;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&matr2[i][j]),matr2[i][j]%=3;
        memset(matr3,0,sizeof(matr3));

            for (int i=1;i<=n;i++){
            for (int k=1;k<=n;k++){
                if(matr1[i][k])
                    for (int j=1;j<=n;j++){
                         matr3[i][j]+=matr1[i][k]*matr2[k][j];
                    }
            }
            }
            for (int i=1;i<=n;i++){
                printf("%d",matr3[i][1]%3);
                    for (int j=2;j<=n;j++){
                        printf(" %d",matr3[i][j]%3);
                    }
                printf("\n");
            }
    }
    return 0;
}

1005
http://acm.hdu.edu.cn/showproblem.php?pid=4915
题意:
给一个括号的串,包括( ) 和? ,问当需要构成匹配的串时,我们只能构成为唯一的,不能构成合法的,还是能够成很多种。

>
??
????
(??
Unique
Many
None

看了别人的代码,反正当时wa了两发,用模拟做的,看了别人贪心写的很简单

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<string.h>
#include<map>
#include<set>
using namespace std;
#define ll __int64
using namespace std;

#define N 1000005
 /*
从前扫一遍,记录最大和最小的可能的左括号的值
如果最小值>最大值,则必定不行

从后扫一遍,同样记录最大和最小的可能的左括号的值
如果最小值>最大值,no

最后再扫一遍
对于每个i
a[i][0],b[i][0] 代表[1,i]左括号最小的个数,和[i+1,len]右括号最小的个数
他们中的最大值 =l

a[i][1],b[i][1] 代表[1,i]左括号最多的个数,和[i+1,len]右括号最多的个数
他们中的最小值 =r
l<r
如果前者大于后者,则不行

如果后者大于前者则有多重解
如果相等则为唯一解  * */

char s[N];
int a[N][2];  //存左括号 最小 0  最大 1
int b[N][2];  //
int len,flag;

void ans(int i)
{
    if(i==1) printf("Unique\n");
    else if(i==2) printf("Many\n");
    else printf("None\n");
}

int main()
{
    //freopen("1.txt","r",stdin);
    while(~scanf("%s",s+1))
    {
        len = strlen(s+1);
        if(len&1){
             printf("None\n");
             continue;
        }
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        flag = 1;
        for(int i=1;i<=len;i++)
        {
            a[i][0]=a[i-1][0]; a[i][1]=a[i-1][1];
            if(s[i]=='(')           //出现( ,最小最多都+1
                a[i][0]++,a[i][1]++;
            else if(s[i]==')') {
                if(!a[i-1][0])  //控制最小的(应该>0, 但不控制最多的,以及第一个?=(
                    a[i][0]=1;
                else
                    a[i][0]--;
                a[i][1]--;
            }
            else if(s[i]=='?'){
                if(!a[i-1][0])  //把?当)看
                    a[i][0]=1;
                else
                    a[i][0]--;
                a[i][1]++;    //对于最多的吧 ?当(看
            }
           if(a[i][0]>a[i][1]){  // 例如:  )( ,?))(??
               flag=0;
               break;
           }
        }
        if(flag==0){
             printf("None\n");
             continue;
        }
        for(int i=len;i>=1;i--)
        {
//              b[i][0] = b[i+1][0]; b[i][1] = b[i+1][1];
            if (s[i] == ')')
                b[i-1][0] = b[i][0] + 1, b[i - 1][1] = b[i][1] + 1;
            else if (s[i] == '(') {
                if (!b[i][0])
                    b[i-1][0] = 1;
                else
                    b[i - 1][0] = b[i][0] - 1;
                b[i - 1][1] = b[i][1] - 1;
            } else if (s[i] == '?') {
                if (!b[i][0])
                    b[i - 1][0] = 1;
                else
                    b[i - 1][0] = b[i][0] - 1;
                b[i - 1][1] = b[i][1] + 1;
            }
            if(b[i][0]>b[i][1]){
                flag=0;
                break;
            }
        }
        if(flag==0){
            printf("None\n");
            continue;
        }
        int l,r;
        flag = 1;
        for(int i=1;i<=len;i++)
        {
/*          printf("i=%d a0 b=%d %d\n",i,a[i][0],b[i][0]);
            printf("     a1 b=%d %d\n",a[i][1],b[i][1]);
            l = max(a[i][0],b[i][0]); //左右括号的最小值
            r = min(a[i][1],b[i][1]); //
            if(l>r) {flag=0;break;}
            if(l<r) {flag=2;break;}
            因为已知ab[i][1]>=ab[i][0]
            所以可以改写
            */
            if(a[i][0]>b[i][1] || b[i][0] >a[i][1]){
                flag=0;break;
            }
            if(a[i][1] >b[i][0] && b[i][1]>a[i][0]){
                flag=2;break;
            }
        }
        if(flag==0)
            printf("None\n");
        else if(flag==1)
            printf("Unique\n");
        else if(flag==2)
            printf("Many\n");
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值