JNU周练1013

CodeForces 337A

 给出n、m(n<=m)和m个数字,在m个数字中选n个数字,令这n个数字中最大数与最小数值差最小。

数据量小,直接暴力

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    int a[60], n, m;
    cin >> n >> m;
    for(int i = 0; i < m; i++)
        cin >> a[i];
    sort(a, a+m);
    int min = 1005;
    for(int i=0; i<=m-n; i++)
    {
        if(a[i+n-1] - a[i] < min)
            min = a[i+n-1] - a[i];
    }
    cout << min << endl;
    return 0;
}
View Code 

CodeForces 337B

给出屏幕与电影的宽高比,电影按比例缩放,尽量占满屏幕,求屏幕没被占的面积的比例。输出要求:分子分母互质。

找规律,无论是电影适应屏幕还是屏幕适应电影,得出的比例都是一样的。同时注意两比例相同时输出0/1。

#include <iostream>
using namespace std;

int gcd(int x, int y)
{
    int r;
    while(y!=0)
    {
        r = x%y;
        x = y;
        y = r;
    }
    return x;
}

int main()
{
    int a, b, c, d, temp;
    cin >> a >> b >> c >> d;
    a = a * d;
    c = c * b;
    if(a < c)  
    {
        temp = a;
        a = c;
        c = temp;
    }
    c = a - c;
    temp = gcd(a,c);
    a /= temp;
    c /= temp;
    cout << c << "/" << a << endl;
    return 0;
}
View Code 


CodeForces 337C

/*
    题意:
    一人去参加比赛。每答对一题得一分。连续答对k题时先加一分然后总分数乘2然后连续答对题数归0。
    然后给你题目总数n和他答对题目的个数m问你他能得的最低分是多少。

    要获得最低分,要尽量避免连续答对k题,或者让连续答对k题的情况尽量出现在分数少的时候
    方法是:设答对为1,答错为0,以k-1个"1"和1个"0"为一组从后往前排列,
    最后得出两部分,一部分是x组k-1个"1"和1个"0",另一部分为连续y个1
    则n = k * x + y;  m = (k-1) * x + y;  ---> 得 x = n - m

    第一部分好求:(k-1) * x
    第二部分需要找规律:
    另z = y / k,则有z*k次答对,取z = 1, 2, 3,...总分数如下
    那么分数变化为:2*k,(2*k+k)*2,((2*k+k)*2+k)*2......。
    抽象出来这就是一个数列递推公式为:a[z]=2*(a[z-1]+k)。
    展开移项后得:a[z]+2*k=2*(a[z-1]+2*k)。设c[z]=a[z]+2*k。那么c[z]/c[z-1]=2。等比数列。
    而c[0]=a[0]+2*k=2k。那么c[z]=2*k*2^z。所以a[z]=k*2^(z+1)-2*k。

    数据大,要用到快速幂


*/

 注意中间数大,要开long long

#include <iostream>
using namespace std;

const long long MOD = 1000000009;

//计算a^bmodn     
long long modexp_recursion(long long a,long long b,long long n)     
{    
    long long t = 1;

    if (b == 0)
        return 1;

    if (b == 1)
         return a%n;

    t = modexp_recursion(a, b>>1, n);

    t = t*t % n;

    if (b&0x1)
    {    
        t = t*a % n;
    }

    return t;
 } 

int main()
{
    long long n, m, k;
    cin >> n >> m >> k;
    long long a = m / (k-1);
    if(a <= n - m)
        cout << m << endl;
    else
    {
        long long ret = 0;
        a = n - (n-m)*k;
        long long b = a / k;
        if(b>0)
        {
            //cout << "b:" << b << endl;
            
//cout << modexp_recursion(2, b, MOD) << endl;
            ret = 2 * k * modexp_recursion(2, b, MOD) - 2*k;
            ret = ret % MOD;
            //cout << "ret:" << ret << endl;
        }
        ret = (ret + (n-m) * (k-1)) % MOD;
        ret = (ret + (a-a/k*k)) % MOD;
        cout << ret << endl;
        //cout << "aaa:" << modexp_recursion(2,100,MOD) << endl;
    }
    return 0;
}
View Code 
CodeForces 337D

题意:给一棵n个结点的树,任意两个节点的距离是指连接两点的最短的边数

在树上的某个结点有一个“恶魔之书”,这本书会让距离它d以内的节点都受到影响

已知有m个节点收到了影响,问最多有几个结点可能放着“恶魔之书”?

据说是树形dp,看题解知道大概思路后,自己写代码,挑了无数bug过了。。

规定点1为根节点 

dp[i][0] --- 代表节点 i 子树中距 i 最远的受影响点和 i 的距离。

dp[i][1] --- 上述的次远距离

dp[i][2] --- 代表节点 i 子树以外的部分 距 i 最远的受影响点和 i 的距离。

若某点dp[i][0] 和 dp[i][2]均小于或等于影响范围d,表示该点满足条件。

 dp[i][0] 和 dp[i][1]好求,dp[i][2] 则要综合(1) i 的祖先节点和(2)其父节点的其他子树的情况。

状态转移方程: 

u(父)--- v(子)

fa(父) --- u, i (子)

dp[u][0] = max(dp[v][0] + 1)

dp[u][2] =  max(dp[fa][2], {dp[fa][0] or dp[fa][1]} + 1)   

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100010
#define M 200010

int head[N], vid[N], vis[N], eNum, n, m, d;
struct Edge
{
    int e;
    int next;
}edge[M];

int dp[N][3];

void AddEdge(int u, int v)
{
    edge[eNum].e = v;
    edge[eNum].next = head[u];
    head[u] = eNum++;
}

void init()
{
    int temp, u, v;
    eNum = 0;
    memset(head, -1sizeof(head));
    memset(vis, 0sizeof(vis));
    memset(dp, -1sizeof(dp));
    cin >> n >> m >> d;
    for(int i=1; i<=m; i++)
    {
        cin >> temp;
        vis[temp] = 1;
    }
    for(int i=1; i<n; i++)
    {
        cin >> u >> v;
        AddEdge(u, v);
        AddEdge(v, u);
    }
}

void dfs1(int u, int fa)
{
    if(vis[u]==1) dp[u][0] = 0;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].e;
        if(v == fa) continue;
        dfs1(v, u);
        if(dp[v][0] + 1 > dp[u][0])
        {
            if(dp[v][0]!=-1)
            {
                dp[u][1] = dp[u][0];
                dp[u][0] = dp[v][0] + 1;
            }
        }
        else if(dp[v][0] + 1 > dp[u][1] && dp[v][0] != -1)
        {
            dp[u][1] = dp[v][0] + 1;
        }

    }
}

void dfs2(int u, int fa)
{
    if(vis[u]==1 && dp[u][2]==-1) dp[u][2] = 0;
    for(int i=head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].e;
        if(v == fa) continue;
        if(dp[u][2]!=-1) dp[v][2] = dp[u][2] + 1;
        if(dp[v][0]+1 == dp[u][0])
        {
            if(dp[u][1] != -1)
                dp[v][2] = max(dp[v][2], dp[u][1]+1);
        }
        else if(dp[u][0]!=-1)
            dp[v][2] = max(dp[v][2], dp[u][0]+1);
        dfs2(v, u);
    }
}

int main()
{
    init();
    dfs1(10);
    dfs2(10);
    int ans = 0;
    for(int i=1; i<=n; i++)
        if(dp[i][0]<=d && dp[i][2]<=d)
            ans++;
    //for(int i=1; i<=n; i++)
    
//{
    
//    cout << dp[i][0] << "   " << dp[i][1] << "   " << dp[i][2] << endl;
    
//}
    cout << ans << endl;
    return 0;
}
/*
9 4 3
1 2 8 9
1 5
5 4
4 3
3 2
5 6
6 7
7 8
8 9

*/
View Code 

 CodeForces 337E

 题意,给你一颗n个数,构建一颗树,包含所有数,满足根结点等于儿子结点的乘积,并且所有叶子结点都是素数。

关键点:对每个a[i]分解质因子,得出因子个数。在此基础上建树,由于n<=8,所以直接dfs枚举所有情况,得出最小的结点数。 

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct Num
{
    long long b;
    int c;
}num[10];
int n; //存输入
int a[80000], index;
long long leftt[10];//标记剩余多少
int vis[10], sum, ans_min;

int prime(int x)
{
    int flag = 0;
    for(int i=2; i*i<=x; i++)
    {
        if(x%i==0)
        {
            flag = 1;
            break;
        }
    }
    if(flag)
        return 0;
    return 1;
}

//筛选法求1000000内素数
int prime1(int x)
{
    int flag = 0;
    for(int i=0; a[i]*a[i]<=x; i++)
    {
        if(x%a[i]==0)
        {
            flag = 1;
            break;
        }
    }
    if(flag)
        return 0;
    return 1;
}

bool cmp(Num a, Num b)
{
    return a.c < b.c;
}

void dfs(int t)
{
    //cout << "t: " << t << endl;
    if(t == n)
    {
        int ret = sum, retn = n;
        for(int i=1; i<=n; i++)
        {
            if(vis[i]!=0)
            {
                ret -= num[i].c;
                retn --;
            }
        }
        if(retn>1) ret++;
        if(ret < ans_min) ans_min = ret;
        //------test
        
//if(ret==8)
        
//{
        
//    for(int i=1; i<=n; i++)
        
//    {
        
//        cout << vis[i]<<endl;
        
//    }
        
//}
        return ;
    }

    for(int i=t+1; i<=n; i++)
    {
        long long temp = leftt[i];
        if(leftt[i] >= num[t].b && leftt[i]%num[t].b==0)
        {
            leftt[i] /= num[t].b;
            vis[t] = i;
        }
        dfs(t+1);
        if(temp!=leftt[i])
        {
            leftt[i] *= num[t].b;
            vis[t] = 0;
        }
    }
}

int main()
{
    long long flag;
    index = 0;
    for(int i=2; i<=1000; i++)
    {
        if(prime(i))
            a[index++] = i;
    }
    for(int i=1001; i<=1000000; i++)
    {
        if(prime1(i))
            a[index++] = i;
    }

    cin >> n;
    for(int i=1; i<=n; i++)
        cin >> num[i].b;
    for(int i=1; i<=n; i++)
    {
        num[i].c = 0; flag = num[i].b;
        for(int j=0; j<index && flag>1; )
        {
            if(flag%a[j]==0)
            {
                flag /= a[j];
                num[i].c ++;
            }
            else
            {
                j++;
            }
        }
        //原数<=10^12,除遍10^6内的素数后,若该数仍大于0,则一定有且仅一个10^6+1~10^12的质因子
        if(flag>1) num[i].c++;
    }
    sort(num+1, num+n+1, cmp);

    sum = 0, ans_min = 1000000000;
    memset(vis,0,sizeof(vis));
    for(int i=1; i<=n; i++)
    {
        leftt[i] = num[i].b;
        sum += num[i].c;
        if(num[i].c!=1) sum++;
    }
    //cout << "sum: " << sum << endl;
    dfs(1);
    cout << ans_min << endl;

    //for(int i=1; i<=n; i++)
    
//    cout << num[i].b << ": " << num[i].c << endl;
    
//cout << index << endl;
    
//cout << a[index-1] << endl;
    return 0;
}
View Code 
原文地址:https://www.cnblogs.com/byluoluo/p/3369584.html