1010 I love permutation
题意
I love permutation
给一个素数p和一个整数a。
用
b
x
=
(
a
∗
x
)
b_x=(a*x)
bx=(a∗x)%p; 构建一个b序列,长度p-1(
1
<
=
x
<
=
p
−
1
1<=x<=p-1
1<=x<=p−1)
求b序列的逆序对数模2的结果。
思路
结果是对二取余。 说明说明逆序对数要是奇数(输出1)或偶数(输出0)
首先观察一下式子 b x = ( a ∗ x ) b_x=(a*x) bx=(a∗x) (不考虑模p) 那怎么入手呢? 从官方题解:
我们考虑他是正是负数,上述式子如果一组是逆序对数,那么 ( π ( i ) − π ( j ) ) / ( i − j ) (π(i)-π(j))/(i-j) (π(i)−π(j))/(i−j)就是负数,反之就是正数。 然后,就是上述的递推。
上述的公式第三步为什么呢?注意这里是同余的符号。 π ( i ) = a ∗ i π(i)=a*i π(i)=a∗i%p, π ( j ) = a ∗ j π(j)=a*j π(j)=a∗j%p, 根据模的性质可得到
( a ∗ i − b ∗ j ) (a*i-b*j) (a∗i−b∗j)%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(p−1)/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
题意
给a,b数组, 产生c数组,其中
C
k
C_k
Ck=max{
A
i
∗
B
j
A_i*B_j
Ai∗Bj} (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
题意
思路
先预处理出
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科目,复习j天,挂科k门的,能获得的最高的分数。
第一个状态的方程简单的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[i−1][j−tian][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[i−1][j−tian][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;
}