2023华中科技大学程序设计新生赛

最后战绩

在这里插入图片描述
在这里插入图片描述
完成7题,I题矩阵快速幂不会,太菜了

A题 简单的加法乘法计算题

在这里插入图片描述

使用dp和优先队列(或者线段树)
d p [ i ] = { d p [ i − j ] , 1 ≤ j ≤ n d p [ i / m i ] , i % m i = 0 dp[i] = \left\{ \begin{aligned} dp[i-j] &,1\leq j \leq n \\ dp[i/m_i]&, i \% m_i =0 \end{aligned} \right. dp[i]={dp[ij]dp[i/mi],1jn,i%mi=0

#include<iostream>
#include<cstring>
#include<set>
#include<queue>
using namespace std;
const int N =5e6+10;
int y,n,m;
int p[10]; 
int dp[N];
int tree[N<<2];
//void add(int i, int v,int l,int r,int p){
//	
//}
int main(){
	scanf("%d%d%d",&y,&n,&m);
//	memset(dp, -1, sizeof dp);
//	memset(tree, 0x3f, sizeof tree);
	priority_queue<pair<int,int>, vector<pair<int,int> >, greater<pair<int,int> > > q;
	for(int i=0;i<m;i++){
		scanf("%d",&p[i]);
	}
	for(int i=1;i<=n;i++){
		dp[i] = 1;
		q.push({1, i});
	}
	for(int i=n+1;i<=y;i++){
		while(!q.empty() && q.top().second <i-n)q.pop();
		dp[i] = 1+ q.top().first;
		
		for(int j=0;j<m;j++){
			if(i%p[j]==0){
				dp[i] = min(dp[i], 1+dp[i/p[j]]);
			}
		}
		q.push({dp[i], i});
//		cout<<dp[i]<<" ";
	}
	printf("%d", dp[y]);
	
} 

F题 新取模运算

在这里插入图片描述

( 1 , . . . , p ) , ( p + 1 , . . . , 2 p ) , ( 2 p + 1 , . . . , 3 p ) 循环出现, d p [ i ] 表示 i ! ⊕ p , 则 d p [ j ∗ p ] = j ∗ d p [ p ] (1,...,p) ,(p+1, ... ,2p),(2p+1,...,3p)循环出现,dp[i]表示i!\oplus p ,则dp[j*p] = j * dp[p] (1,...,p),(p+1,...,2p),(2p+1,...,3p)循环出现,dp[i]表示i!p,dp[jp]=jdp[p]

#include<iostream>
#include<cstring>
#include<set>
#include<queue>
using namespace std;
const int N =1e6+10;
int p1;
long long p[N]; 
long long get(long long i,long long j){
	long long cur = i, ans = 1;
	while(j){
		if(j&1){
			ans=(ans*cur)%p1;
		}
		j>>=1;
		cur=(cur*cur)%p1;
	}
	return ans;
}
int main(){
	int t;
	cin>>t>>p1;
	p[1] = 1;
	for(int i=2;i<p1;i++){
		p[i] = p[i-1] * i % p1;
//		cout<<i<<" "<<p[i]<<endl; 
	}
	if(p1>=1)
		p[p1] = p[p1-1];
	p[0] = 1;
	while(t--){
		long long n;
		cin>>n;
		long long ans = 1;
		while(n){
			long long b = n / p1;
			int y = n%p1;
			ans = get(p[p1], b)*p[y]%p1 *ans %p1;
			n = b;
		}
		
		cout<<ans<<endl;
	}
} 

C题 排列排序问题

在这里插入图片描述

顺序遍历,当前数和前一个数绝对值差不等于1,则加1

#include<iostream>
#include<cstring>
#include<cmath>
#include<set>
#include<queue>
using namespace std;
const int N =1e6+10;
int p[N];
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>p[i];
	} 
	bool f = true;
	int ans = 0;
	int i=1;
	while(i<n){
		if(abs(p[i] - p[i-1])!=1){
			ans++;
			i++;
		}else{
			i++;
		}
	}
	cout<<ans;
} 

L题 Azur Lane

在这里插入图片描述

计算最少递减组数t,则t天之前输出-1,同时得到 p r e _ s u m 1 , . . . , p r e _ s u m i pre\_sum_1,...,pre\_sum_i pre_sum1,...,pre_sumi前缀和,遍历1到 p r e _ s u m i pre\_sum_i pre_sumi,如何当前值j不在前缀和中,则放入优先队列中,t天后面的每一次从优先队列中找最小值加上去就行了。

#include<iostream>
#include<cstring>
#include<cmath>
#include<set>
#include<queue>
#include<vector>
using namespace std;
const int N =1e6+10;
int p[N];
int a[N], pre[N];
int dd[N];
int main(){
	int m,k;
	cin>>m>>k;
	for(int i=0;i<m;i++){
		cin>>p[i];
	}
	vector<int> v;
	int i = 1;
	while(i<m){
		int t = 1;
		while(i<m && p[i]<=p[i-1]){
			i++;
			t++;
		}
		v.push_back(t);
		if(i<m)
		{
			i++;
			if(i>=m){
				v.push_back(1);
			}
		}
	}
	int n = v.size();
	set<int> s1;
	long long sum = 0;
	for(int i=0;i<n;i++){
		pre[i+1]+=pre[i] + v[i]; 
		s1.insert(pre[i+1]);
		sum += pre[i+1];
	}
	int cnt=0;
	for(int i=1;i<=pre[n];i++){
		if(s1.find(i)==s1.end()){
			dd[cnt++] = i;
		}
	} 
	for(int i=1;i<n;i++){
		cout<<-1<<" ";
	}
	int ct = 0;
	for(int i=n;i<=m;i++){
		cout<<sum<<" ";
		sum+= dd[ct++];
	}
} 

D题 网格染色

在这里插入图片描述

我是这样想的,最优策略是尽可能让所有正方形染上两条边,当自己是最后让所有正方形染上两条边的人,则自己一定赢,因为另外一个人必定开始染第三条边,而后自己染四条边,让所有正方形染上两条边需要2*n是个偶数,重边算两个边,则假如第一个人选择染非重边,则第二个人也选择染非重边,第一个人选择染重边,则第二个人也选择染重边,则最后一定是第一个人开始染第三条边,也就是后手一定赢

#include<iostream>
#include<cstring>
#include<cmath>
#include<set>
#include<queue>
#include<vector>
using namespace std;

int main(){
	int n;
	cin>>n;
	cout<<"Kelin";

} 

I题 Fujisaki讨厌数学

在这里插入图片描述

设 x n + x − n 为 f ( n ) , 则有 f ( n ) = k ∗ f ( n − 1 ) − f ( n − 2 ) , 设x^n+x^{-n}为f(n),则有f(n) =k*f(n-1) -f(n-2), xn+xnf(n),则有f(n)=kf(n1)f(n2), n比较大使用快速幂,比赛结束之后才补上

#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <stack>
#include <map>
#include <cstring>
#include <stack>
#include <cmath>
using namespace std;
const int N=2e5+10;
long long p[2][2];
int k;
int m;
void qmi(long long n){
    long long cur[2][2];
    cur[0][0] = k, cur[0][1] = -1;
    cur[1][0] = 1, cur[1][1] = 0;
    long long ans[2][2];
    ans[0][0] = 1, ans[0][1] = 0;
    ans[1][0] = 0, ans[1][1] = 1;
    int tmp[2][2];
    while(n){
        if(n&1){
            // ans=(mul())
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    p[i][j] = 0;
                    for(int k=0;k<2;k++){
                        p[i][j] = ((p[i][j] + cur[i][k]*ans[k][j]%m)%m + m)%m;
                    }
                }
            }
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    ans[i][j] = p[i][j];
                }
            }
        }
        n>>=1;
        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++){
                tmp[i][j] = 0;
                for(int k=0;k<2;k++){
                    tmp[i][j] = ((tmp[i][j] + cur[i][k]*cur[k][j]%m)%m + m)%m;
                }
            }
        }
        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++){
                cur[i][j] = tmp[i][j];
            }
        }
    }
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            p[i][j] = ans[i][j];
        }
    }
    
}
int main()
{
  std::ios::sync_with_stdio(false);
  std::cin.tie(0);
  long long n;
  cin>>m>>k>>n;
  if(n==0){
      cout<<2;
  }else{
  qmi(n-1);
    cout<<(p[0][0] * k%m + p[0][1]*2%m)%m<<endl; 
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_43983809

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值