2021“MINIEYE杯”中国大学生算法设计超级联赛(2)补题

1010 I love permutation

题意

I love permutation
给一个素数p和一个整数a。
b x = ( a ∗ x ) b_x=(a*x) bx=(ax)%p; 构建一个b序列,长度p-1( 1 < = x < = p − 1 1<=x<=p-1 1<=x<=p1)
求b序列的逆序对数模2的结果。

思路

结果是对二取余。 说明说明逆序对数要是奇数(输出1)或偶数(输出0)

首先观察一下式子 b x = ( a ∗ x ) b_x=(a*x) bx=(ax) (不考虑模p) 那怎么入手呢? 从官方题解:
在这里插入图片描述
我们考虑他是正是负数,上述式子如果一组是逆序对数,那么 ( π ( i ) − π ( j ) ) / ( i − j ) (π(i)-π(j))/(i-j) (π(i)π(j))/(ij)就是负数,反之就是正数。 然后,就是上述的递推。
在这里插入图片描述
上述的公式第三步为什么呢?注意这里是同余的符号。 π ( i ) = a ∗ i π(i)=a*i π(i)=ai%p, π ( j ) = a ∗ j π(j)=a*j π(j)=aj%p, 根据模的性质可得到
( a ∗ i − b ∗ j ) (a*i-b*j) (aibj)%mod= ( π ( i ) − π ( j ) ) (π(i)-π(j)) (π(i)π(j))%mod 后面就很清楚啦。算出 s g n ( π ) = a ( p − 1 ) / 2 m o d sgn(π)=a^{(p-1)/2} mod sgn(π)=a(p1)/2mod
P P P 的奇偶即可,就得出了结果。 ( s g n ( π ) sgn(π) sgn(π)) 结果只有

AC代码如下

//submitted by HNUST026
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
ll gcd(ll a,ll b){ return b? gcd(b,a%b):a;}
const int N=2e6+10;
const ll mod=998244353;
using namespace std;
ll read(){
    ll s = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)) s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
    return s * f;
}
ll  p;
ll qpow(int x,int y){
	ll ans=1;
	while(y){
		if(y&1){
		   ans=(ans*x)%p;
		}
		x=(x*x)%p;
		y>>=1;
	}
//	cout<<ans;
    return ans;
}
void solve(){
	ll a;
	a=read();p=read();
	ll ans=qpow(a,(p-1)/2);
	if(ans%2==0){
		cout<<"1"<<endl;
	}else{
		cout<<"0"<<endl;
	}
}
int main() {
//  freopen("out.txt","w",stdout);
  int T;
  T=read();
  while(T--)
  solve();
  return 0;
}

1011 I love max and multiply

I love max and multiply

题意

给a,b数组, 产生c数组,其中 C k C_k Ck=max{ A i ∗ B j A_i*B_j AiBj} (i&j>=k)
求数组c之和。

思路

在这里插入图片描述
问题转化就是: 求D数组。 思路是什么呢? eg:D[10010(2)] 我希望他是尽量往大的方向取, 构造dp方程,D[10010]
可以往D[11010] or D[10110] or D[10011] 这些状态转移,然后同理也知道D[11010] or D[10110]
or D[10011] 也是转移。 说白了D[i]什么含义呢:
一个j>=i的数,只要满足i的二进制位置上是1的,j相应的位置也必须是1就可。

AC代码如下:

#include<bits/stdc++.h>
#define ll long long
#define ld long double
#define ull unsigned long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define LL long long
ll gcd(ll a,ll b){ return b? gcd(b,a%b):a;}
const int N=(1<<20)+10;
const ll P=998244353;
const ll INF=2e9;
const LL inf=1e18;
ll read(){
    ll s = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)) s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
    return s * f;
}
using namespace std;
void get_min(ll &x,ll y){
	if(x>y) x=y;
}

void get_max(ll &x,ll y){
	if(x<y) x=y;
}
ll n,m;
ll A[N],B[N];
ll a[N],b[N];
ll sum[N],ans[N];
void solve(){
	n=read();
	rep(i,0,n-1){
		a[i]=read();
		A[i]=a[i];
	}
	rep(i,0,n-1){
		b[i]=read();
		B[i]=b[i];
	}
	m=1;
	// n: 10110   那么m是 100000 
	while(m<n) m<<=1;
	rep(i,n,m){
		A[i]=-INF;B[i]=-INF;
		a[i]=INF;b[i]=INF;
	}
	// 从大到小遍历 
	for(int i=m-1;i>=0;i--){
		// 移动的位数
		for(int j=1;j<m;j<<=1){
			// 满足if条件就是  i:10101  j可以是:00010 01000
			if((i&j)==0){
				// A,a,B,b 每个都是D数组咯,不过各自含义不同咯 
				 //dp转移过程。 
				A[i]=max(A[i],A[i^j]);
				a[i]=min(a[i],a[i^j]);
				B[i]=max(B[i],B[i^j]);
				b[i]=min(b[i],b[i^j]);
			}
		}
	}
	sum[n]=-inf;
	// 找乘起来之后的最大值。
	// 四种情况都要有:  A:-1 a:-3  B:5 b:4 在这种情况下,A*b是最大的。 
	for(int i=n-1;i>=0;i--){
		sum[i]=-inf;
		if(A[i]!=-INF and B[i]!=-INF){
			sum[i]=max(sum[i],(ll)(A[i]*B[i]));
		}
		if(A[i]!=-INF and b[i]!=INF){
			sum[i]=max(sum[i],(ll)(A[i]*b[i]));
		}
		if(a[i]!=INF and B[i]!=-INF){
			sum[i]=max(sum[i],(ll)(a[i]*B[i]));
		}
		if(a[i]!=INF and b[i]!=INF){
			sum[i]=max(sum[i],(ll)(a[i]*b[i]));
		}
//		sum[i]=max(sum[i],sum[i+1]);
	}
	ll ans=0;
	ll com=-inf;
	for(int i=n-1;i>=0;i--){
		com=max(com,sum[i]);
		ans=(ans+com)%P;
	}
	ans=(ans+P)%P;
	cout<<ans<<endl;
	return ;
   
}
int main (){
//  freopen("in.txt","r",stdin);
//  freopen("out.txt","w",stdout);
  int T;
  T=read();
  while(T--)
  solve();
  return 0;
}

1008 I love exam

题意

I love exam

思路

先预处理出 d p [ i ] [ j ] , 科 目 , 天 数 , 获 得 的 最 高 的 分 数 dp[i][j],科目,天数,获得的最高的分数 dp[i][j],
然后 f [ i ] [ j ] [ k ] 前 i 科 目 , 复 习 j 天 , 挂 科 k 门 的 , 能 获 得 的 最 高 的 分 数 。 f[i][j][k]前i科目,复习j天,挂科k门的,能获得的最高的分数。 f[i][j][k]i,jk
第一个状态的方程简单的dp的背包
考虑第二个:注意一个细节,就是不选第i科目,那么必然会挂科,其实就是 d p [ i ] [ 0 ] dp[i][0] dp[i][0]需要考虑到。
状态转移:
1.当k>=1时 f [ i ] [ j ] [ k ] = m a x ( d p [ i ] [ j ] [ k ] , d p [ i − 1 ] [ j − t i a n ] [ k − ( m a r k > 60 ? 0 : 1 ) ] + m a r k ) f[i][j][k]=max(dp[i][j][k],dp[i-1][j-tian][k- (mark > 60 ? 0:1)]+mark) f[i][j][k]=max(dp[i][j][k],dp[i1][jtian][k(mark>60?0:1)]+mark)
2.k==0时,那么mark>=60 f [ i ] [ j ] [ k ] = m a x ( d p [ i ] [ j ] [ k ] , d p [ i − 1 ] [ j − t i a n ] [ k ] + m a r k ) f[i][j][k]=max(dp[i][j][k],dp[i-1][j-tian][k]+mark) f[i][j][k]=max(dp[i][j][k],dp[i1][jtian][k]+mark)
AC代码如下:

#include<bits/stdc++.h>
#define ll long long
#define ld long double
#define ull unsigned long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
ll gcd(ll a,ll b){ return b? gcd(b,a%b):a;}
const int N=2e5+10;
const ll P=1e9+7;
ll read(){
    ll s = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)) s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
    return s * f;
}
using namespace std;
struct node{
	int  x;
	int y;
};
ll n,m;
map<string,int> mp;
vector<node> a[55];
int dp[55][550]; // 科目 天数  分数 
int f[55][550][10];// 科目  天数 挂科数 
void solve(){
	mp.clear();
	rep(i,0,54){
		a[i].clear();
	}
	n=read();
	string s;
    rep(i,1,n){
		cin>>s;
		mp[s]=i;
	}
	m=read();
	// mark day
	int x,y;
	rep(i,1,m){
		cin>>s;
		x=read();
		y=read();
        int cnt=mp[s];
        a[cnt].push_back(node{x,y});
	}
	int t,p;
	t=read(); p=read();
    memset(dp,-0x3f,sizeof(dp));
   
	rep(i,1,n) dp[i][0]=0;
	rep(i,1,n){
		for(int j=0;j<a[i].size();j++){
			for(int tian=t;tian>=a[i][j].y;tian--){
				// 分数上限是100分, 所以超出的分数,但是只要用的天数少,还是可以 
				dp[i][tian]=min(100,max(dp[i][tian],dp[i][tian-a[i][j].y]+a[i][j].x));
			}
		}
		// for(int j=120;j>=100;j--) dp[i][j]=min(dp[i][j],dp[i][j+1]);
	}
//	 cout<<"dasda"<<endl;
	memset(f,-0x3f,sizeof(f));
	f[0][0][0]=0; 
	rep(i,1,n){    //科目 
		rep(j,1,t){  //第几天数 
			rep(k,0,p){     //挂几门科 
				rep(tian,0,j){ //枚举以前的天数到现在的状态 
					if(dp[i][tian]>=60){
						f[i][j][k]=max(f[i][j][k],f[i-1][j-tian][k]+dp[i][tian]);
					}else{
						if(k){
							f[i][j][k]=max(f[i][j][k],f[i-1][j-tian][k-1]+dp[i][tian]);
						}
					}
				}
			}
		}
	}
	int ans=-1;
	rep(i,1,t){
         rep(j,0,p){
			 ans=max(ans,f[n][i][j]);
		 }
	}
	cout<<ans<<endl;
}
int main (){
//   freopen("in.txt","r",stdin);
//   freopen("out.txt","w",stdout);
  int T;
  T=read();
  while(T--)
  solve();
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

axtices

谢谢您的打赏

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

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

打赏作者

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

抵扣说明:

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

余额充值