2.13总结

P1077 [NOIP2012 普及组] 摆花

题目描述

小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 �m 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的 �n 种花,从 11 到 �n 标号。为了在门口展出更多种花,规定第 �i 种花不能超过 ��ai 盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。

试编程计算,一共有多少种不同的摆花方案。

输入格式

第一行包含两个正整数 �n 和 �m,中间用一个空格隔开。

第二行有 �n 个整数,每两个整数之间用一个空格隔开,依次表示 �1,�2,⋯ ,��a1,a2,⋯,an

输出格式

一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对 106+7106+7 取模的结果。

输入输出样例

输入 #1复制

2 4

3 2

输出 #1复制

2

说明/提示

【数据范围】

对于 20%20% 数据,有 0<�≤8,0<�≤8,0≤��≤80<n≤8,0<m≤8,0≤ai≤8。

对于 50%50% 数据,有 0<�≤20,0<�≤20,0≤��≤200<n≤20,0<m≤20,0≤ai≤20。

对于 100%100% 数据,有 0<�≤100,0<�≤100,0≤��≤1000<n≤100,0<m≤100,0≤ai≤100。

NOIP 2012 普及组 第三题

思路

摆花时摆当前的花时,需要在摆放完上一盆花产生的结果中进行累加 由于传球游戏只能从左右两个相邻位置相加,所以数字的范围不会太大。但是摆花时,如果当前的花有 10 盆,那么当前的花摆放 0、1、2…10 产生的都是不同的结果,都需要考虑,所以可能的情况是非常多的,可能的情况多,那种对应的方案数也会大,取模就变得很必要了。

根据上述对题目的分析,递推公式也很显然了,假设状态转移都保存在数组 dp[n][m] 中,第一维表示当前对第 i 种花作分析,第二维表示当前摆放的所有的花盆数量和。递推公式如下:

dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + … dp[i-1][j-ai]

dp[i][j] 的含义是放第 i 种花时,花盆总数刚好是 j ,第 i 种花最多有 ai 盆,所以 dp[i-1] 中只要花盆数量大于 j - ai 的情况都能凑成 dp[i][j]。参照别人的递推过程

代码如下

#include<stdio.h>
#define MAX 1000007
int n,m;
int a[110],f[110][110];
int min(int x,int y)
{
    return (x<y)?x:y;
}
int main()
{
    int i,j,k;
    scanf("%d %d",&n,&m);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
        f[0][0]=1;
    for(i=1;i<=n;i++)
        for(j=0;j<=m;j++)
        for(k=0;k<=min(j,a[i]);k++)
        f[i][j]=(f[i][j]+f[i-1][j-k])%MAX;
    printf("%d",f[n][m]);
}

P2758 编辑距离

题目描述

设 �A 和 �B 是两个字符串。我们要用最少的字符操作次数,将字符串 �A 转换为字符串 �B。这里所说的字符操作共有三种:

  1. 删除一个字符;

  1. 插入一个字符;

  1. 将一个字符改为另一个字符。

�,�A,B 均只包含小写字母。

输入格式

第一行为字符串 �A;第二行为字符串 �B;字符串 �,�A,B 的长度均小于 20002000。

输出格式

只有一个正整数,为最少字符操作次数。

输入输出样例

输入 #1复制

sfdqxbw

gfdgw

输出 #1复制

4

说明/提示

对于 100%100% 的数据,1≤∣�∣,∣�∣≤20001≤∣A∣,∣B∣≤2000。

思路

这个题目看到的时候根本没有思路,看了题解

题解 P2758 【编辑距离】 - Esther! - 洛谷博客 (luogu.com.cn)

#include<stdio.h>
char A[2010],B[2010];
int dp[2010][2010];
int min(int x,int y)
{
    return (x<y)?x:y;
}
int main()
{
    scanf("%s%s",A,B);
    int len1,len2,i,j;
    len1=strlen(A);
    len2=strlen(B);
    dp[0][0]=0;
    for(i=0;i<=len1;i++)
        dp[0][i]=i;
    for(i=0;i<=len2;i++)
        dp[i][0]=i;
        for(i=1;i<=len2;i++)
        {
           for(j=1;j<=len1;j++)
           {
               if(A[j-1]==B[i-1])
                dp[i][j]=dp[i-1][j-1];
               else
                dp[i][j]=dp[i-1][j-1]+1;
               dp[i][j]=min(min(dp[i-1][j]+1,dp[i][j-1]+1),dp[i][j]);
           }
        }
        printf("%d",dp[len2][len1]);
}

B - 签到题2

Problem Statement

You are given a simple undirected graph with �N vertices and �M edges. The vertices are numbered 11 to �N, and the �i-th edge connects vertex ��Ai and vertex ��Bi. Let us delete zero or more edges to remove cycles from the graph. Find the minimum number of edges that must be deleted for this purpose.

What is a simple undirected graph?

What is a cycle?

Constraints

  • 1≤�≤2×1051≤N≤2×105

  • 0≤�≤2×1050≤M≤2×105

  • 1≤��,��≤�1≤Ai,Bi≤N

  • The given graph is simple.

  • All values in the input are integers.

Input

The input is given from Standard Input in the following format:

NM�1A1​�1B1​�2A2​�2B2​⋮⋮��AM​��BM

Output

Print the answer.

Sample 1

Inputcopy

Outputcopy

6 7

1 2

1 3

2 3

4 2

6 5

4 6

4 5

2

One way to remove cycles from the graph is to delete the two edges between vertex 11 and vertex 22 and between vertex 44 and vertex 55.

There is no way to remove cycles from the graph by deleting one or fewer edges, so you should print 22.

Sample 2

Inputcopy

Outputcopy

4 2

1 2

3 4

0

Sample 3

Inputcopy

Outputcopy

5 3

1 2

1 3

2 3

1

思路:

测试的时候只注意查找,忘记合并,一直错了好久

#include<stdio.h>
#define MAX 200010
int fa[MAX];
void init(int n)
{
    for (int i = 1; i <= n; ++i)
        fa[i] = i;
}

int find(int x)
{
    return x == fa[x] ? x : (fa[x] = find(fa[x]));
}

void merge(int i, int j)
{
    fa[find(i)] = find(j);
}
int main()
{
    int N,M,sum=0;
    scanf("%d %d",&N,&M);
    init(N);
    for(int i=1;i<=M;i++)
    {
        int a,b;
        scanf("%d %d",&a,&b);
        if(find(a)!=find(b))
            merge(a,b);
            else
                sum++;
    }
    printf("%d\n",sum);
}

C - 简单的构造题

The sum of digits of a non-negative integer �a is the result of summing up its digits together when written in the decimal system. For example, the sum of digits of 123123 is 66 and the sum of digits of 1010 is 11. In a formal way, the sum of digits of �=∑�=0∞��⋅10�a=i=0∑∞ai⋅10i, where 0≤��≤90≤ai≤9, is defined as ∑�=0∞��i=0∑∞ai.

Given an integer �n, find two non-negative integers �x and �y which satisfy the following conditions.

  • �+�=�x+y=n, and

  • the sum of digits of �x and the sum of digits of �y differ by at most 11.

It can be shown that such �x and �y always exist.

Input

Each test contains multiple test cases. The first line contains the number of test cases �t (1≤�≤100001≤t≤10000).

Each test case consists of a single integer �n (1≤�≤1091≤n≤109)

Output

For each test case, print two integers �x and �y.

If there are multiple answers, print any.

Sample 1

Inputcopy

Outputcopy

5

1

161

67

1206

19

1 0

67 94

60 7

1138 68

14 5

Note

In the second test case, the sum of digits of 6767 and the sum of digits of 9494 are both 1313.

In the third test case, the sum of digits of 6060 is 66, and the sum of digits of 77 is 77.

思路

还是我想的太简单了,直接除2时不行的,比如19就不行,然后参照了别人的代码勉强写出来

#include<stdio.h>

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        if(n%2==0)
            printf("%d %d\n",n/2,n/2);
        else if(n%10!=9)
            printf("%d %d\n",n/2,n-n/2);
            else
            {
                int a[10]={0},b[10]={0};
                int j;
                int m=n;
                for(j=0;m>0;j++)
                {
                    a[j]=m%10;
                    m=m/10;
                }
                int k=j;
                int f=1;
                for(j=0;j<k;j++)
                {
                    if(a[j]%2==0)
                    {
                        b[j]=a[j]/2;
                        continue;
                    }
                    b[j]=a[j]/2+f;
                    if(f==1)
                    f=0;
                    else
                    f=1;
                }
                int x=0;
                if(a[k-1]==1&&b[k-2]<a[k-2]-b[k-2])
                {x=1;k--;}
                for(j=k-1;j>=0;j--)
                {
                    x=x*10+b[j];
                }
                printf("%d %d\n",x,n-x);
            }
    }
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值