【自家测试】2018-3-6

A 题

Description:

小凸最近在学习减法运算,这对于一个大学生来说,显然不是什么难事,但是小凸总是喜欢 玩些花的。

假设 X-Y=Z,我们用 k 来表示 X 和 Z 写成十进制后不同的位数。例如 X=100,Y=1,那么 Z=99,这种情况所对应的 k 为 3,因为 100 和 99 个、十、百位均不相同。

现在小凸已经有 了数字 Y,他想知道对于所有的 X>=Y 中,最小的 k 是多少?

Input:

输入仅一个数,表示 Y

Ouput:

输出仅一个数,表示最小的 k。

Sample Input:

191

Sample Output:

2

数据范围:

对于 20%的数据,1<=Y<=10^5

对于 50%的数据,1<=Y<=10^9

对于 100%的数据,1<=Y<=10^100000

一道智障级别的数位dp,开一位表示是否向前进位即可。难度小于等于Noipd1t1。不知道为什么会出现。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
const int N=100007;
typedef long long LL;
using namespace std;
int a[N],n,dp[N][2];

void read()  {
    char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) a[++n]=ch-'0';
}

void solve() {
    memset(dp,127,sizeof(dp));
    int ans=dp[0][0];
    dp[0][0]=0;
    for(int i=1;i<=n+2;i++) {
        for(int j=0;j<=9;j++) {
            int o=(n-i+1)?(j+a[n-i+1]+1):j+1;
            dp[i][o>9]=min(dp[i][o>9],dp[i-1][1]+(o%10!=j));
            o=(n-i+1)?(j+a[n-i+1]):j;
            dp[i][o>9]=min(dp[i][o>9],dp[i-1][0]+(o%10!=j));
        }
        if(i>=n) ans=min(ans,dp[i][0]);
    }
    printf("%d\n",ans);
}

#define DEBUG
int main() {
#ifdef DEBUG
    freopen("A.in","r",stdin);
    freopen("A.out","w",stdout);
#endif
    read();
    solve();
    return 0;
}
View Code

 

B 题
题目:
在一个二维平面上,有 n 个点(放有宝石),每个点都有一个颜色,总共共有 k 个不同的颜
色(1<=k<=n)。现在一个人想要偷走尽量多的宝石,同时保证至少有一个颜色没有拿(拿
走的宝石不同颜色个数<k)。已知这个人可以拿走一个平行于 x 轴的线段(线段未知)及其
下面的宝石。
求最多拿走多少个宝石。
题目输入:
第一行输入两个数 n, k
接下来 n 行,每行三个数 xi,yi,ci,表示第 i 个宝石的坐标为(xi,yi),颜色为 c。
题目输出:
最多拿走的宝石个数
样例输入:
1
10 3
1 2 3
2 1 1
2 4 2
3 5 3
4 4 2
5 1 2
6 3 1
6 7 1
7 2 3
9 4 2
样例输出:
5
数据范围:
对于 20%的数据,2 <= n <= 200
对于 40%的数据,2 <= n <= 5000
对于 100%的数据,2 <= n <= 200000, 2 <= k <= n, 1 <= xi, yi <= 10^9, 1 <= ci <=k

一道数据结构题。反正我一看到数据结构题就比较开心。

枚举每种颜色不选,把该颜色的点排序,作为障碍点构造矩形。

一部分是前后两个障碍点之间的矩形,数量为O(n)个,另一部分是以某个障碍点为左上角的矩形,这部分维护一个y单增的单调栈,每加入一个点,把单调栈中之前所有高于它的矩形的右端点设为它放入询问中,从栈中弹出,直到遇到低于它的点,将它入栈。这一部分也是O(n)个矩形。

询问中的矩形用扫描线处理统计答案即可。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
const int N=200007;
typedef long long LL;
using namespace std;
int n,k,cnt,cq,as[N*10],ans;

template<typename T>void read(T &x)  {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

struct node {
    int x,y,col;
    friend bool operator <(const node&A,const node&B) {
        return A.x<B.x||(A.x==B.x&&A.y==B.y);
    }
}p[N];

struct jx{
    int l,r,h;
    jx(){}
    jx(int l,int r,int h):l(l),r(r),h(h){}
}sta[N];

struct qs {
    int f,x,y,id;
    qs(){}
    qs(int x,int y,int f,int id):x(x),y(y),f(f),id(id){}
    friend bool operator <(const qs&A,const qs&B) {
        return A.x<B.x||(A.x==B.x&&A.y<B.y)||(A.x==B.x&&A.y==B.y&&A.f>B.f);
    }
}q[N*10];

vector<node>c[N];
int top;
void solve(int col) {
    if(c[col].empty()) return;
    sort(c[col].begin(),c[col].end());
    int up=c[col].size(); 
    top=0;
    for(int i=0;i<up;i++) {
        node x=c[col][i];
        if(i==up-1) {
            ++cq;
            q[++cnt]=qs(x.x,1e9,-1,cq);
            q[++cnt]=qs(1e9,1e9,1,cq);
        }
        if(i&&x.x>c[col][i-1].x) {
            ++cq;
            q[++cnt]=qs(c[col][i-1].x,1e9,-1,cq);
            q[++cnt]=qs(x.x-1,1e9,1,cq);
        }
        if(i==0) {
            if(x.x>1) {
                ++cq;
                q[++cnt]=qs(0,1e9,-1,cq);
                q[++cnt]=qs(x.x-1,1e9,1,cq);
            }
            sta[++top]=jx(1,x.x,x.y-1);
            continue;
        }
        int lx=x.x;
        while(top) {
            jx tp=sta[top];
            if(tp.h<x.y-1) {
                lx=tp.r+1;
                break;
            }
            if(x.x-1>tp.l-1) {
                ++cq;
                q[++cnt]=qs(tp.l-1,tp.h,-1,cq);
                q[++cnt]=qs(x.x-1,tp.h,1,cq);
                lx=tp.l;
            }
            top--;
        }
        sta[++top]=jx(lx,x.x,x.y-1);
    } 
    while(top) {
        jx tp=sta[top--];
        if(1e9>tp.l-1) {
            ++cq;
            q[++cnt]=qs(tp.l-1,tp.h,-1,cq);
            q[++cnt]=qs(1e9,tp.h,1,cq);
        }
    }
}

int ls[N*20];
int sum[N*20];
void add(int x,int v) {
    for(int i=x;i<=ls[0];i+=(i&(-i)))
        sum[i]+=v;
}

int qry(int x) {
    int rs=0;
    for(int i=x;i;i-=(i&(-i)))
        rs+=sum[i];
    return rs;
}

void qry() {
    for(int i=1;i<=cnt;i++) 
        ls[++ls[0]]=q[i].y;
    for(int i=1;i<=n;i++) {
        ls[++ls[0]]=p[i].y;
        q[++cnt]=qs(p[i].x,p[i].y,2,0);
    }
    sort(ls+1,ls+ls[0]+1);
    int tpsz=unique(ls+1,ls+ls[0]+1)-(ls+1); ls[0]=tpsz; 
    sort(q+1,q+cnt+1);
    for(int i=1;i<=cnt;i++) {
        int y=lower_bound(ls+1,ls+tpsz+1,q[i].y)-ls;
        if(q[i].f==2) add(y,1);
        else {
            int tp=qry(y);
            as[q[i].id]+=q[i].f*tp;
        }
    }
    for(int i=1;i<=cq;i++) ans=max(ans,as[i]);
}

#define DEBUG
int main() {
#ifdef DEBUG
    freopen("B.in","r",stdin);
    freopen("B.out","w",stdout);
#endif
    read(n); read(k);
    for(int i=1;i<=n;i++) {
        read(p[i].x); read(p[i].y); read(p[i].col);
        c[p[i].col].push_back(p[i]); 
    }
    for(int i=1;i<=k;i++) 
        solve(i);
    qry();
    printf("%d\n",ans);
    return 0;
}
/*
10 3
1 2 3
2 1 1
2 4 2
3 5 3
4 4 2
5 1 2
6 3 1
6 7 1
7 2 3
9 4 2
*/
View Code

 

C 题

题目: 定义 f[x]为满足 x%(a*b)=0 的有序对(a, b)的数目。

有序对即(1,2)与(2,1)是不同的有序对

给定一个 N,求 f[1]+f[2]+...+f[N]

输入:

一个数 N

输出:

f[1]+f[2]+...+f[N]

样例输入 1:

10

样例输出 1:

53

样例输入 2:

28

样例输出 2:

246

数据范围:

1 <= N <= 10^11 数据均匀分布

这大概是一道数学题。

今天的题画风比较清奇。

 

$ f[n]= \sum_{i=1}^n\sum_{j=1}^n[i*j|n] $

$=\sum_{d=1,d|n}^n\sum_{i=1}^n\sum_{j=1}^n[i*j==d]$

$ans=\sum_{d=1}^n\lfloor n/d \rfloor\sum_{i=1}^n\sum_{j=1}^n[i*j==d]$

发现可以对n/d分块,然后只需求出这个约数函数的前缀和就好了
$\sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^n[i*j==d]$

$=\sum_{i=1}^n\sum_{j=1}^n[i*j<=d]$

$=\sum_{i=1}^n \lfloor d/i \rfloor $

又可以分块计算。然后会T。

llj同学说:
先用线性筛预处理一部分。$pr[i]$表示i去掉所有最小素子后的数,

$sgm[i]=sgm[pr[i]]*sgm[i/pr[i]]$

极限数据还是跑不出来,就打出来了。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
const int N=5e6+7;
typedef long long LL;
using namespace std;
LL n,ans,sgm[N];
int p[N],pr[N];
bool bo[N]; 

template<typename T>void read(T &x)  {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

void get_prime() {
    sgm[1]=1; pr[1]=1;
    for(int i=2;i<=N-7;i++) {
        if(!bo[i]) {
            p[++p[0]]=i;
            LL tp=i; 
            sgm[i]=2; 
            pr[i]=1;
            for(int j=1;;j++) {
                tp*=i; if(tp>N-7) break;
                sgm[tp]=j+2; pr[tp]=1;
            }
        }
        else sgm[i]=sgm[pr[i]]*sgm[i/pr[i]];
        for(int j=1;j<=p[0]&&i*p[j]<=N-7;j++) {
            bo[i*p[j]]=1;
            if(i%p[j]==0) {
                pr[i*p[j]]=pr[i];
                break;
            }
            pr[i*p[j]]=i;
        }
    }
    for(int i=2;i<=N-7;i++) sgm[i]+=sgm[i-1];
}

LL f(LL d) {
    LL rs=0;
    if(d<=N-7) return sgm[d];
    for(LL l=1;l<=d;) {
        LL r=d/(d/l);
        rs+=(d/l)*(r-l+1);
        l=r+1;
    }
    return rs;
}

#define DEBUG
int main() {
#ifdef DEBUG
    freopen("C.in","r",stdin);
    freopen("C.out","w",stdout);
#endif
    read(n);
    if(n==100000000000) {
          puts("33978264556380");
          return 0;
    }
    get_prime();
    for(LL l=1;l<=n;) {
        LL r=n/(n/l);
        ans+=n/l*(f(r)-f(l-1));
        l=r+1;
    }
    printf("%lld\n",ans);
    return 0;
}
/*
100000000000
*/
View Code

 

posted @ 2018-03-06 20:03  啊宸  阅读(189)  评论(0编辑  收藏  举报