文远知行杯广东工业大学第十六届程序设计竞赛(题解)

文远知行杯广东工业大学第十六届程序设计竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

A:思维题

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e4 + 10;
ll n,m,l,r;
ll s[N][N];
int main()
{
    scanf("%lld%lld",&n,&m);
    if(n == 1 || n == 2)
    {
        while (m--)
        {
            cout<<0<<endl;
        }
         
    }else{
        while (m--)
        {
           scanf("%lld%lld",&l,&r);
           if(l == r)
           {
               cout<<n%l<<endl;
               continue;
           }
           else{
              for(int i = 2 ; i <= n; i++)
              {
               ll mid = ((n) / i) + 1;
               if(l <= mid && r >= mid)
               {
                   cout<<n%mid<<endl;
                   break;
               }else if(l > (n/i + 1))
               {
                   cout<<n % l<<endl;
                   break;
               } 
              } 
            }
        } 
    }
    return 0;
}

A题 题意:一共用n个数,从a[1] = n % 1 a[2] = n % 2 …… a[n] = n % n 再给定一个区间问该区间里的最大值 eg: n = 14 14 - 1 * 14 14 - 2 * 6 14 - 3 * 4 14 - 4 * 3 14 - 5 * 2 14 - 6 * 2 14 - 7 * 2 14 - 8 * 1 14 - 9 * 1 14 - 10 * 1 14 - 11 * 1 14 - 12 * 1 14 - 13 * 1 14 - 14 * 1 发现一个规律 14 6 4 3 2 2 2 1 1 1 1 1 1 1 0 2 2 2 4 2 0 7 6 5 4 3 2 1 n会在(n/2+1,n)范围内递减 同理(n/3+1,n/2)范围内也是递减 (n/4+1,n/3)递减 (n/n+1,n/n-1)递减 从第一个开始 n % i 可以看成 n - i * x a[1] = n - 1 * x a[2] = n - 2 * x …… a[n] = n - n * x(这里x取n*x最接近n的情况) x由n=0开始到n结束,当i * 2 = n时下一步边无法乘2,只能乘以1便会出现一个极大值 同理,当i * 3 = n时,下一步无法乘3,只能乘2也会出现一个极大值

F:数论题

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
typedef long long LL;
int main()
{
    int T;
    cin >> T;
    while(T -- ) {
       int n;
       cin >> n;
       int p, c, ans = 1;
       while(n -- ) {
           cin >> p >> c;
           int z = ((LL)c * 2 + 1) % mod;
           ans = ((LL)ans * z) % mod;
       }
       printf("%d\n", ans);
    }
 return 0;
}

F:题意 输出一组p和c 其中p为质数 求 pow(p1,i1) * pow(p2,i2) * pow(p3,i3) + ……+pow(pn,in) = x 求其中多少对互质 eg 2 * 2 + 1 * 3 = 12 {(1, 1),(1, 2),(1, 3),(1, 4),(1, 6),(1, 12),(2, 1),(2, 3),(3, 1),(3, 2),(3, 4),(4, 1),(4, 3),(6, 1),(12, 1)共15对} 定理:一个大于1的正整数均可以由若干个质数相乘 所以 所给的p和c就是x被分解为质因数的情况 由质数和其不包含其的数是互质 当p1,c1,p2,c2 (1 * (c1+1)(c2+1))+ (c1 * (c2+1)) + (c2 * (c1+1))+ (c1* c2 * 1) = (c1 + 1 + c1)(c2 + 1) + (c2 * (c1+1+c1)) = (2c1 + 1)(2c2 + 2) 对于p1,c1,p2,c2 (1 * (c1+1)(c2+1)(c3+1)) + (c1 * (c2+1)(c3+1)) + (c2 * (c1+1)(c3+1)) + (c3 *(c1+1)(c2+1)) + (c1 * c2 * (c3+1)) +(c1 * c3 * (c2+1)) + (c2 * c3 * (c1+1)) + (c1 * c2 * c3 * 1) = (c3 + 1 + c3) {(1 * (c1+1)(c2+1))+ (c1 * (c2+1)) + (c2 * (c1+1))+ (c1* c2 * 1)} =(2c3 + 1)(2c2 + 1)(2c3 + 1)

I题:贪心的dp问题

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000005;
int n, m, k;
int a[N];
ll dp[N][2];

int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for (int i = k + 1; i <= n; i++)
    {
        dp[i][0] = max(dp[i - k][0], dp[i - k][1]);//这个不选等于上一个不选,上上个选,或者上一个选,上上个不选
        dp[i][1] = dp[i - k][0] + a[i] + a[i - k];//选这个等于(上一个不选)选这个
      //cout << dp[i][0] << " " << dp[i][1] << endl;//选这个和不选这个
    }
    ll ans = 0;
    for (int i = n - k + 1; i <= n; i++)//1 3 5 7 …… 2n + 1 这些点都会因为前一个受不受影响而改变,所以ans可以加上每一段不互不影响的
    {
        //cout<<dp[i][0]<<" "<<dp[i][1]<<endl;
        ans += max(dp[i][0], dp[i][1]);
    }    
    cout << ans;
    return 0;
}

I题题意:钩子长度为k 可以同时抓取两个(i,i+k),但不能只抓取一个, 核心:其影响了谁,求取互不影响的几组

影响因素上取分析 当 i i + k 当存在i + 2k时你便要分析取i i+k,还是i+k i+2k 所以你用数组dp进行dp [i ,1]表示该点取,那么它dp[i,1] = dp[i - k , 0] + a[i] + a[i - k]; dp[i , 0] = max(dp[i , 1] + dp[i,0]) 所以最后可以进行对最后一组(n - k + 1 , n)对这几组可以互不影响的几组数据进行相加,从而求取最大值

E: 前缀和dp问题

#include<bits/stdc++.h>
#define IOS std::ios::sync_with_stdio(false);
#define tcase int ttt;scanf("%d",&ttt);while(ttt--)
typedef long long ll;
using namespace std;
const ll N = 2e5+9;
const ll inf = 1e16;
const ll mod = 1e9+7;
int mx[N];
int pre[20][N];
char s[N];
int n;
void pro(){
	int sum = 0;
	for(int i = 1 ; i <= n ; i++){  //对从i开始的10步走法之内
		sum = 0; // 用于计数,表示该位置能走到且为声明值为0
		for(int j = i ; j <= i + 9 && sum >= 0 ; j++) //小于9步且生命值不能为0
        {
			if(s[j] == '0') sum--;
			else sum++;
			if(sum == 0)
            {
				pre[(j-i+1)][i] = 1; //存在从i走j-i+1步这种情况
			}
		}
	}
    for(int i = 1 ; i <= 10 ; i++)
    {
		for(int j = 1 ; j <= n ; j++)
        {
			pre[i][j] = pre[i][j] + pre[i][j-1]; 
            //前缀和  加上上一个点走了这些距离,如果pre[i][r-i+1]>pre[i][l-1]说明从l到r中多除了一些个这些距离的方案
		}
	}
}
int main(){
	scanf("%d",&n);
	scanf("%s",s+1);
	pro();
	int q;
	scanf("%d",&q);
	while(q--){
		int l,r;
		scanf("%d %d",&l,&r);
		int i;
		for(i = 10 ; i >= 1 ; i--)//从最大的开始遍历
        {     
			if(r - i + 1 >= l - 1)//保证步数位于l到r之内
            {  
				if(pre[i][r-i+1] - pre[i][l-1])//如果从r-i+1走i步大于从l-1走i步,说明存在这种情况
                {                              //要不就是从某个位置到r,要不就是从l到某个位置,或者从某个位置到某个位置
					break;
				}	
			}
		}
		printf("%d\n",i);
	}
	return 0;
}

  思路:dp[i,j] 表示从j走i个距离的情况是否存在(因为i<=10) 预先处理所有情况从任何一个位置走i步情况是否存在 对所有i步的情况进行前缀和处理 对于所给的l和r dp[i,r-i+1] > dp[i,l-1] 说明一件事说明能走i步的情况在l到r的位置存在,因为是相加,所以存在时,那么一定会大于dp[i.l-1]

J:构造函数(纯公式推导)

#include<bits/stdc++.h>

using namespace std;

const int MOD = 1e9 + 7;

int mpow(int x , int y = MOD - 2) {
    int ret = 1;
    while (y) {
        if (y & 1) ret = 1ll * ret * x % MOD;
        x = 1ll * x * x % MOD;
        y >>= 1;
    }
    return ret;
}

int main() {
    cin.tie(nullptr)->sync_with_stdio(0);

    int N , m;
    cin >> N >> m;

    int u = m + N;

    int sum = 0;
    for (int i = 1 ; i <= N ; i++) {
        int x;
        cin >> x;
        sum += x;
        if (sum >= MOD) sum -= MOD;
    }

    if (m + N < N + sum) {
        cout << "0\n";
    } else {
        int ans = 1 , d = 1;
        for (int i = 1 ; i <= N + sum ; i++) {
            ans = 1ll * ans * (u - i + 1) % MOD;
            d = 1ll * d * i % MOD;
        }
        d = mpow(d);
        cout << 1ll * ans * d % MOD << endl;
    }
    return 0;
}

题意:

 

eg 3 5 n = 3 m = 5 A : 1 2 1 B:2 1 2 1 2 1 2 2 1 1 3 1 2 + 1 + 2 + 3 = 8 想法: 题目要求累积的累加 , 累积我们可以看成一个卷积

 

k我们代表 0 ,1, 2,3…… m f(x) = b0x^0 + b1x^1 + b2 x^2 + ……+ bk x^k 这时候这个构造函数我们只需要将b0 + b1 + b2 + b3 + b4 +……+ bk的和 上满那个例子 b0 = 0 b1 = 0 b2 = 0 b3 = 0 b4 = 1 b5 = 2 + 2 + 3 = 7

现在我们需要求对应的b0 b1 b2 b3 b4 b5 对A中的ai进行牛顿二项式构造 m代表正无穷 C(i , a0) f(x) = C(0,a0) x^0 + C(1,a0) x^1 + C(2,a0) x^2 + …… +C(n,a0)x^m C(i , a1) f(x) = C(0,a1) x^0 + C(1,a1) x^1 + C(2,a1) x^2 + …… +C(n,a1)x^m C(i , a2) f(x) = C(0,a2) x^0 + C(1,a2) x^1 + C(2,a2) x^2 + …… +C(n,a2)x^m …… C(i , an) f(x) = C(0,an) x^0 + C(1,an) x^1 + C(2,an) x^2 + …… +C(n,an)x^m 这里用卷积可以求出对应 x^0 x^1 x^2 x^3 x^4 …… x^k

对于该例子: (C(0,a0) * C(0,a1) * C(0,a2)) x^0 + (C(1,a0) * C(0,a1) * C(0,a2) + C(0,a0) * C(1,a1) * C(0,a2) + C(0,a0) * C(0,a1) * C(1,a2) ) x^1 + () x^2 同理 因为前面都为0所以我们直接来写x^5的情况

a0 = 1 a1 = 2 a2 = 1

5 0 0 0 5 0 0 0 5 4 1 0 4 0 1 0 4 1 1 4 0 1 0 4 0 1 4 3 2 0 3 0 2 0 3 2 2 3 0 2 0 3 0 2 3 …… 其实写了这些你会发现基本都为0 所以我们写出几个不为0的情况 2 2 1 1 3 1 1 2 2 其余情况均为0

(C(2,a0) * C(2,a1) * C(1,a2) + C(1,a0) + C(3,a1) + C(1,a2) + C(1,a0) * C(2,a1) * C(2,a2)) x^5 里面为7

所以我们便可以生成一个构造函数(说白了k就是在后面生成的构造函数中截取了一段)

 

上面公式推导中p = ai + 1 中 1/(1 - x) ^ p = 1/(1 - x) ^ai +1 = (ai + i , ai) x^i 和我们要的(i,ai)不同 这里i代表C(i , ai)中的i,方便卷积后直接取1到k的和,所以我们强行乘以ai以方便以后求和 (ai + i , ai) x^i * x^ai;

这样做不会有漏掉的,因为i从0开始 i+ai从ai开始,因为C(i,ai)中i大于等于ai才会不为0,其余均为0,所以不会出现漏掉的情况

然后求前k个ai的和,a1+a2+a3……+ ak-1+ak 因为最后推出式子为(k + t + n - 1 , n + t - 1) x^(k+t) 因为我们要找0到k,所以k+t = x 我们找x从0到k (x + n - 1 , n + t - 1) 这里就属于换元了,和下面的一样

 

在最后一步操作就是单纯的换元,在该题,无法采用换元,因为i和i+ai中i为同一个所以我们换也始终多ai 所以我们直接乘以x^ai得到 以后我们要找的x^k 前的ak了

 

这里解释对最后一步求b1+b2+b3+……+bk的和 k = 0~m (k+n-1,n+t-1) = (m + n - 1 + 1 , n+t-1+1) = (m+n,n+t) (对于L的变换只进行自变量,对于k的变换为全部的常量)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值