第五周解题报告

233 阅读4分钟

P1464 Function

Function

题目描述

对于一个递归函数 w(a,b,c)w(a,b,c)

  • 如果 a0a \le 0b0b \le 0c0c \le 0 就返回值1 1
  • 如果 a>20a>20b>20b>20c>20c>20 就返回 w(20,20,20)w(20,20,20)
  • 如果 a<ba<b 并且 b<cb<c 就返回w(a,b,c1)+w(a,b1,c1)w(a,b1,c) w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c)
  • 其它的情况就返回 w(a1,b,c)+w(a1,b1,c)+w(a1,b,c1)w(a1,b1,c1)w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1)

这是个简单的递归函数,但实现起来可能会有些问题。当 a,b,ca,b,c 均为 1515 时,调用的次数将非常的多。你要想个办法才行。

注意:例如 w(30,1,0)w(30,-1,0) 又满足条件 11 又满足条件 22,请按照最上面的条件来算,答案为 11

输入格式

会有若干行。

并以 1,1,1-1,-1,-1 结束。

输出格式

输出若干行,每一行格式:

w(a, b, c) = ans

注意空格。

样例 #1

样例输入 #1

1 1 1
2 2 2
-1 -1 -1

样例输出 #1

w(1, 1, 1) = 2
w(2, 2, 2) = 4

提示

数据规模与约定

保证输入的数在 [9223372036854775808,9223372036854775807][-9223372036854775808,9223372036854775807] 之间,并且是整数。

保证不包括 1,1,1-1, -1, -1 的输入行数 TT 满足 1T1051 \leq T \leq 10 ^ 5

using namespace std;
typedef long long ll;
ll rpt[25][25][25];
ll w(ll a,ll b,ll c)
{
    if(a<=0||b<=0||c<=0) return 1;
    else if(rpt[a][b][c]!=0) return rpt[a][b][c];
    else if(a>20||b>20||c>20) rpt[a][b][c]=w(20,20,20);
    else if(a<b&&b<c) rpt[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
    else rpt[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
    return rpt[a][b][c];
}
int main()
{
    ll a,b,c;
    while(scanf("%lld%lld%lld",&a,&b,&c)==3){
        memset(rpt,0,sizeof(rpt));
        if(a==-1&&b==-1&&c==-1) break;
        printf("w(%lld, %lld, %lld) = ",a,b,c);
        if(a>20) a=21;
        if(b>20) b=21;
        if(c>20) c=21;
        printf("%lld\n",w(a,b,c));
    }
    return 0;
}

P1928 外星密码

外星密码

题目描述

有了防护伞,并不能完全避免 2012 的灾难。地球防卫小队决定去求助外星种族的帮助。经过很长时间的努力,小队终于收到了外星生命的回信。但是外星人发过来的却是一串密码。只有解开密码,才能知道外星人给的准确回复。解开密码的第一道工序就是解压缩密码,外星人对于连续的若干个相同的子串 X\texttt{X} 会压缩为 [DX]\texttt{[DX]} 的形式(DD 是一个整数且 1D991\leq D\leq99),比如说字符串 CBCBCBCB\texttt{CBCBCBCB} 就压缩为 [4CB]\texttt{[4CB]} 或者[2[2CB]]\texttt{[2[2CB]]},类似于后面这种压缩之后再压缩的称为二重压缩。如果是 [2[2[2CB]]]\texttt{[2[2[2CB]]]} 则是三重的。现在我们给你外星人发送的密码,请你对其进行解压缩。

输入格式

输入一行,一个字符串,表示外星人发送的密码。

输出格式

输出一行,一个字符串,表示解压缩后的结果。

样例 #1

样例输入 #1

AC[3FUN]

样例输出 #1

ACFUNFUNFUN

提示

【数据范围】

对于 50%50\% 的数据:解压后的字符串长度在 10001000 以内,最多只有三重压缩。

对于 100%100\% 的数据:解压后的字符串长度在 2000020000 以内,最多只有十重压缩。保证只包含数字、大写字母、[]

#include<bits/stdc++.h>
using namespace std;
string read()
{
	int n;
	string s="",s1;
	char c;
	while (cin>>c)//一直读入字符,直到Ctrl+z
	{
		if (c=='[')
		{
			cin>>n;//读入D
			s1=read();//读入X
			while (n--) s+=s1;//重复D次X
            //注:上面不能写成while (n--) s+=read();
		}
		else 
		{
			if (c==']') return s;//返回X
		    else s+=c;//如果不是'['和']',那就是X的一个字符,所以加进X
		}
	}
}
int main()//巨短主函数
{
	cout<<read(); 
	return 0;
}

P2437 蜜蜂路线

蜜蜂路线

题目背景

题目描述

一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你:蜜蜂从蜂房 mm 开始爬到蜂房 nnm<nm<n,有多少种爬行路线?(备注:题面有误,右上角应为 n1n-1

输入格式

输入 m,nm,n 的值

输出格式

爬行有多少种路线

样例 #1

样例输入 #1

1 14

样例输出 #1

377

提示

对于100%的数据,1M,N10001 \le M,N\le 1000

#include<bits/stdc++.h>
using namespace std;
int m,n;
int len=1;
int f[1010][1005];
void pus(int x){
    for(int i=1;i<=len;i++){
        f[x][i]=f[x-1][i]+f[x-2][i];
    }
    for(int i=1;i<=len;i++){
        if(f[x][i]>9){
            f[x][i+1]+=f[x][i]/10;
            f[x][i]%=10;
        }
    }
    if(f[x][len+1])len++;
}
int main(){
    cin>>m>>n;
    f[1][1]=1;
    f[2][1]=2;
    for(int i=3;i<=n-m;i++){
        pus(i);
    }
    for(int i=len;i;i--)cout<<f[n-m][i];
    return 0;
}

P1164 小A点菜

小A点菜

题目背景

uim 神犇拿到了 uoi 的 ra(镭牌)后,立刻拉着基友小 A 到了一家……餐馆,很低端的那种。

uim 指着墙上的价目表(太低级了没有菜单),说:“随便点”。

题目描述

不过 uim 由于买了一些书,口袋里只剩 MM(M10000)(M \le 10000)

餐馆虽低端,但是菜品种类不少,有 NN(N100)(N \le 100),第 ii 种卖 aia_i(ai1000)(a_i \le 1000)。由于是很低端的餐馆,所以每种菜只有一份。

小 A 奉行“不把钱吃光不罢休”,所以他点单一定刚好把 uim 身上所有钱花完。他想知道有多少种点菜方法。

由于小 A 肚子太饿,所以最多只能等待 11 秒。

输入格式

第一行是两个数字,表示 NNMM

第二行起 NN 个正数 aia_i(可以有相同的数字,每个数字均在 10001000 以内)。

输出格式

一个正整数,表示点菜方案数,保证答案的范围在 int 之内。

样例 #1

样例输入 #1

4 4
1 1 2 2

样例输出 #1

3

提示

2020.8.29,增添一组 hack 数据 by @yummy

#include <bits/stdc++.h>
using namespace std;
int f[105][10005];
int n,m,v[105],ans;
int dfs(int c,int k){
    if(f[c][k])return f[c][k];
    if(v[c]>k)return 0;
    if(v[c]==k)return 1;
    for(int i=c+1;i<=n;i++)f[c][k]+=dfs(i, k-v[c]);
    return f[c][k];
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>v[i];
    }
    for(int i=1;i<=n;i++){
        ans+=dfs(i, m);
        //cout<<ans<<endl;
    }
    cout<<ans;
    return 0;
}

P1036 [NOIP2002 普及组] 选数

[NOIP2002 普及组] 选数

题目描述

已知 nn 个整数 x1,x2,,xnx_1,x_2,\cdots,x_n,以及 11 个整数 kkk<nk<n)。从 nn 个整数中任选 kk 个整数相加,可分别得到一系列的和。例如当 n=4n=4k=3k=344 个整数分别为 3,7,12,193,7,12,19 时,可得全部的组合与它们的和为:

3+7+12=223+7+12=22

3+7+19=293+7+19=29

7+12+19=387+12+19=38

3+12+19=343+12+19=34

现在,要求你计算出和为素数共有多少种。

例如上例,只有一种的和为素数:3+7+19=293+7+19=29

输入格式

第一行两个空格隔开的整数 n,kn,k1n201 \le n \le 20k<nk<n)。

第二行 nn 个整数,分别为 x1,x2,,xnx_1,x_2,\cdots,x_n1xi5×1061 \le x_i \le 5\times 10^6)。

输出格式

输出一个整数,表示种类数。

样例 #1

样例输入 #1

4 3
3 7 12 19

样例输出 #1

1

提示

【题目来源】

NOIP 2002 普及组第二题

#include<bits/stdc++.h>
using namespace std;
int x[25];
int n,k;
vector<int>ans;
bool isz(int y){
    if(y==0){
        return false;
    }
    if(y==2){
        return true;
    }
    for(int i=2;i<=sqrt(y);i++){
        if(y%i==0){
            return false;
        }
    }
    return true;
}
void backtracking(int k,int n,int type,int sum,int pos){
    if(type==k){
        ans.push_back(sum);
        return ;
    }
    for(int i=pos;i<n;i++){
        sum+=x[i];
        backtracking(k, n, type+1, sum,i+1);
        sum-=x[i];
    }
}
int main(){
    cin>>n>>k;
    int res=0;
    for (int i=0; i<n; i++) {
        cin>>x[i];
    }
    int sum=0;
    backtracking(k, n, 0, sum,0);
    for(int i=0;i<ans.size();i++){
        if(isz(ans[i])){
            res++;
        }
    }
    cout<<res;
    return 0;
}

第338场周赛

6354. K 件物品的最大和

image.png

弱智题

6355. 质数减法运算

image.png

class Solution {
public:
    int mxN = 1000;
    bool primeSubOperation(vector<int>& nums) {
        int n = nums.size();
        //筛质数
        vector<bool> flag(mxN);
        vector<int> primes;
        primes.push_back(0);  /* 特殊处理, 将0加进去 */
        /* 如果2是质数, 则剔除4, 6, 8, 10, ...   */
        /* 如果3是质数, 则剔除9, 12, 15, 18, ... */
        for (int i = 2; i < mxN; ++i) {
            if (!flag[i]) {
                primes.push_back(i);
                for (int j = i * i; j < mxN; j += i) {
                    flag[j] = true;
                }
            }
        }

        for (int i = n - 2; i >= 0; i--) {
            int j;
            /* 从小到大选一个, 满足减去后就严格小于后一个数即可 */
            for (j = 0; j < primes.size(); j++) {
                if (nums[i] > primes[j] && nums[i] - primes[j] < nums[i + 1]) {
                    nums[i] -= primes[j];
                    break;
                }
            }
            /* 找不到合适的质数, 返回false */
            if (j == primes.size()) {
                return false;
            }
        }
        return true;
    }
};

6357. 使数组元素全部相等的最少操作次数

image.png