NOIP模拟题 2016.9.10 [动态规划] [概率] [贪心]

来源:互联网 发布:二维数组全部初始化为0 编辑:程序博客网 时间:2024/05/29 03:59

计算器
LGTB 有一个计算器,只有乘法、等号和部分数字键可以用,现在LGTB 想要用这个计算器按出某些数字,
问最少需要按几下按键。
输入
输入包括两行,第一行为一个整数n,表示LGTB 想要按出的数。
第二行有10 个整数,取值为0 或1。依次表示从0 9 这10 个按键是否可用,0 表示不可用,1 表示可用。
对于100% 的数据,1  n  1000000
输出
输出包括1 行, 表示对应的答案。如果不可能按出n,则输出“Impossible”。
样例
样例输入样例输出
60
0 1 1 0 0 1 0 0 0 0
5
样例输入样例输出
128
1 1 1 1 1 1 1 1 1 1
4
样例说明
对于第一组样例,依次按下1,2,,5,=,得到12  5 =,结果显示60。
对于第二组样例,依次按下1,2,8,=,得到128,结果显示128。
2


首先dp[i*j]=dp[i]+len(j)+1 (j为可行的数) 然后所有的有意义的值都是n的因数,前面两个可以转移到后面的,然后长度最多为sqrt(n),然后中时间复杂度O(n)

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<string>#include<iomanip>#include<ctime>#include<climits>#include<cctype>#include<algorithm>#ifdef WIN32#define AUTO "%I64d"#else#define AUTO "%lld"#endifusing namespace std;#define smax(x,tmp) x=max((x),(tmp))#define smin(x,tmp) x=min((x),(tmp))#define maxx(x1,x2,x3) max(max(x1,x2),x3)#define minn(x1,x2,x3) min(min(x1,x2),x3)typedef long long LL;const int INF=0x3f3f3f3f;const int maxn = 1000005;bool use[15];int dp[maxn];int divisor[maxn],cnt;bool cap[maxn];int n;inline bool check(int num){    if(!num) return use[0];    while(num)    {        if(!use[num%10]) return false;        num/=10;    }    return true;}inline int bit(int num){    if(!num) return 1;    int ret=0;    while(num)    {        ret++;        num/=10;    }    return ret;}inline void init(){    scanf("%d",&n);    memset(dp,0x3f,sizeof(dp));    for(int i=0;i<=9;i++)    {        int tmp;        scanf("%d",&tmp);        use[i] = tmp==1;    }    for(int i=1;i<=n;i++) if(!(n%i)) divisor[++cnt]=i;    for(int i=1;i<=cnt;i++)        if(check(divisor[i])) cap[i]=true,dp[divisor[i]]=bit(divisor[i]);}int dynamic(){    for(int i=1;i<=cnt;i++) if(dp[divisor[i]]^INF)        for(int j=1;j<=cnt;j++) if(cap[j])            if((LL)divisor[i]*divisor[j]<=n) smin(dp[divisor[i]*divisor[j]],dp[divisor[i]]+bit(divisor[j])+1);    if(dp[n]^INF) return dp[n];    else return -1;}int main(){    freopen("calculator.in","r",stdin);    freopen("calculator.out","w",stdout);    init();    int ans = dynamic();    if(~ans) printf("%d",ans+1);    else printf("Impossible");    return 0;}

选数
有两个区间[a, b], [c, d]。现从[a, b] 区间随机选出一个整数x,从[c, d] 区间随机选出一个整数y,问两个数
满足(x + y) mod p = m 的概率有多大。
输入
输入包含一行,有6 个整数,依次为a, b, c, d, p, m。
0  a  b  109
0  c  d  109
0  m < p  109
输出
输出包含一行,包含了一个以“/” 分隔的最简分数。如果分子为0,输出0/1;如果答案是1,输出 1/1。
样例
样例输入 样例输出
0 5 0 5 3 0 1/3
样例输入 样例输出
0 999999 0 999999 1000000 0 1/1000000
样例输入 样例输出
0 3 0 3 8 7 0/1
样例输入 样例输出
3 3 4 4 7 0 1/1
3


取出的两个数之和一定在模p意义下等于m,那么枚举这个和i,可选的数就是 l=max(a,i-d) , r=min(b,i-c) ,一共ans += (r-l+1)

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<string>#include<iomanip>#include<ctime>#include<climits>#include<cctype>#include<algorithm>#ifdef WIN32#define AUTO "%I64d"#else#define AUTO "%lld"#endifusing namespace std;#define smax(x,tmp) x=max((x),(tmp))#define smin(x,tmp) x=min((x),(tmp))#define maxx(x1,x2,x3) max(max(x1,x2),x3)#define minn(x1,x2,x3) min(min(x1,x2),x3)typedef long long LL;LL gcd(LL a,LL b){    if(!b) return a;    return gcd(b,a%b);}LL a,b,c,d,p,m;int main(){    freopen("random.in","r",stdin);    freopen("random.out","w",stdout);    scanf(AUTO AUTO AUTO AUTO AUTO AUTO,&a,&b,&c,&d,&p,&m);    LL numer=0,deno=(LL)(b-a+1)*(d-c+1);    for(LL i=m;i<=b+d;i+=p)    {        if(i<a+c) continue;        LL l=max(a,i-d),r=min(b,i-c);        numer += (r-l+1);    }    LL GCD = gcd(numer,deno);    printf(AUTO"/"AUTO,numer/GCD,deno/GCD);    return 0;}

数对
有n 对数, 依次为(x1, y1), (x2, y2), …, (xn, yn)。现在可以取出其中k 对数,将它们的y 值重新排列,要求
重新排列之后所有数的x 值大于等于y 值。问k 最小为多少。
输入
输入第一行包含一个整数n。
接下来有n 行,每行有两个数,依次表示x 值和y 值。
1  n  105, 1  x, y  109
输出
输出包括一行,如果有解,输出最小的k 值,否则输出-1。
样例
样例输入样例输出
3 3
1 2
2 3
3 1

样例输入 样例输出
5 4
1 5
2 4
3 3
4 2
5 1


贪心,把不能匹配的数对抽出来,放到两个优先队列里面,然后每次尽可能地匹配队首元素,不能匹配的时候就从给定的合法数对里面找出x>y0的所有数对,然后在这些数对里面找到一个y最小的,这样才能使加入这个数对的负担最小(此时保证x能匹配y0)。
然而不能理解标程是写的x>x0,却是对的。。

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<string>#include<iomanip>#include<ctime>#include<climits>#include<cctype>#include<algorithm>#ifdef WIN32#define AUTO "%I64d"#else#define AUTO "%lld"#endifusing namespace std;#define smax(x,tmp) x=max((x),(tmp))#define smin(x,tmp) x=min((x),(tmp))#define maxx(x1,x2,x3) max(max(x1,x2),x3)#define minn(x1,x2,x3) min(min(x1,x2),x3)typedef long long LL;const int INF=0x3f3f3f3f;const int maxn = 100005;struct Back{    int x,y;    bool operator < (const Back t) const { return x < t.x; }};struct Cur{    int x,y;    bool operator < (const Cur t) const { return y >= t.y; }};priority_queue <int> quex,quey;priority_queue <Back> queback;priority_queue <Cur> quecur;int n;int ans;int x[maxn],y[maxn];inline void init(){    scanf("%d",&n); ans=0;    for(int i=1;i<=n;i++)    {        int x0,y0;        scanf("%d%d",&x0,&y0); x[i]=x0,y[i]=y0;        if(x0>=y0) queback.push((Back){x0,y0});        else quex.push(x0),quey.push(y0),ans++; // certain to be divided    }    sort(x+1,x+n+1); sort(y+1,y+n+1);    for(int i=1;i<=n;i++) if(x[i]<y[i])    {        printf("-1");        exit(0);    }}void work(){    while(!quex.empty())    {        if(quex.top()>=quey.top()) { quex.pop(); quey.pop(); continue; } // already matched        while(!queback.empty() && queback.top().x>=quey.top())        {            Back tmp=queback.top(); queback.pop();            quecur.push((Cur){tmp.x,tmp.y}); // waiting to be chosen        }        if(!quecur.empty() && quecur.top().y < quey.top())        {            Cur tmp=quecur.top(); quecur.pop();            quex.push(tmp.x); quey.push(tmp.y);            ans++; // settled pair divided here        }    }    printf("%d",ans);}int main(){    freopen("pair.in","r",stdin);    freopen("pair.out","w",stdout);    init();    work();    return 0;}
0 0
原创粉丝点击