T1
题面
你要不要试试图论
时间限制:4秒 内存限制:256M
题目描述
给出三个整数x, y, P,P为素数,可以重复对x执行如下操作:
选择一个整数z ∈ [1, P − 1],花费∣ x − z ∣元钱,使得x = x ∗ z mod P。
最小需要花费多少钱才能使得x = y?
设 ans(i, j) 为 当 x = i, y = j 时的答案,为了减少输出,你需要输出
输入描述
输入两个整数P,t。
输出描述
输出一个整数表示答案。
输入样例1
2 1
输出样例1
0
样例说明1
ans矩阵为:
0
答案为: 0∗10=00∗10=0
输入样例2
3 233
输出样例2
233
样例说明2
ans矩阵为:
0,1
0,0
答案为
输入样例3
5 233
输出样例3
889807030
样例说明3
ans 矩阵为:
0,1,2,1
0,0,2,0
0,1,0,0
0,1,2,0
答案为:0 233^0 + 1 233^1 + 2 233^2 + 1 233^3 + 0 233^4 + 0 233^5 + 2 233^6 + 0 233^7 +..
数据描述
初次思路
cout<<0;
复盘思路
O(n^3)方法:对于当前数字,推出所有该数字能变成的数字并建图,随后Floyd求最短路并累加即可
AC方法:玄学优化,建图中j范围改为i+-17
code
#include<bits/stdc++.h>
using namespace std;
int p,t,g[2005][2005],f[2005][2005],mod=998244353;
void fl(){
for(int o=1;o<p;o++){
for(int i=1;i<p;i++){
for(int j=1;j<p;j++){
g[i][j]=min(g[i][j],g[i][o]+g[o][j]);
}
}
}
}
int main(){
//freopen("graph.in","r",stdin);
//freopen("graph.out","w",stdout);
memset(g,0x3f,sizeof g);
cin>>p>>t;
for(int j=1;j<p;j++){
g[j][j]=0;
}
for(int i=1;i<p;i++){
for(int j=max(1,i-17);j<min(p,i+17);j++){
g[i][i*j%p]=abs(i-j);
}
}
fl();
for(int i=1;i<p;i++){
for(int j=1;j<p;j++){
cout<<g[i][j]<<' ';
}
cout<<endl;
}
int ans=0,base=1,t;
for(int i=1;i<p;i++){
for(int j=1;j<p;j++){
t=g[i][j]*base%mod;
ans+=t;
ans%=mod;
base*=t;
base%mod;
}
}
cout<<ans;
fclose(stdin);
fclose(stdout);
return 0;
}
T2
题面
数组操作
时间限制:3秒 内存限制:256M
题目描述
输入描述
第一行:输入一个整数n。
第二行:输入n个整数,表示ai 。
输出描述
输出一行答案。
输入样例
5
2 2 2 1 1
输出样例
40
输入样例
88
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3
输出样例
235381964
数据描述
初次思路
O(n!)复杂度枚举,得20分
复盘思路
区间dp
最小花费
dp[i][j]:区间i,j的最小花费
转移:枚举断点k,dp[i][j]=dp[l][k-1]+dp[k+1][r]+f(k)
最小花费的方案数
cnt[i][j]:区间i,j的最小花费的方案数
转移:枚举断点k,cnt[l][r]=cnt[l][k-1]*cnt[k+1][r]*C[r-l][k-l]
#include<bits/stdc++.h>
using namespace std;
int n,dp[1005][1005],a[1005],ans,l,r,cnt[1005][1005],fac[1005],infac[1005],sm[1005],pm[1005];
int mod=998244353;
int qp(int m,int n){
int b = 1;
while(n>0){
if (n & 1)
b = (b*m)%mod;
n=n>>1;
m=(m*m)%mod;
}
return b;
}
int C(int a,int b){
if(a < b) return 0;
if(b == 0 || a == b) return 1;
return fac[a] * infac[a - b] % mod * infac[b] % mod;
}
int main(){
//freopen("array.in","r",stdin);
//freopen("array.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
fac[0]=1;
for(int i=1;i<=n;i++){
fac[i]=fac[i-1]*i%mod;
}
infac[n]=qp(fac[n],mod-2);
for(int i=n-1;i>=0;i--){
infac[i]=infac[i+1]*(i+1)%mod;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cnt[i][j]=1;
}
}
for(int len=1;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
pm[l-1]=0;
for(int i=l;i<=r;i++){
pm[i]=max(pm[i-1],a[i]);
}
sm[r+1]=0;
for(int i=r;i>=l;i--){
sm[i]=max(sm[i+1],a[i]);
}
dp[l][r]=0x3f3f3f3f;
for(int i=l;i<=r;i++){
if(dp[l][r]>dp[l][i-1]+dp[i+1][r]+pm[i-1]+sm[i+1]){
dp[l][r]=dp[l][i-1]+dp[i+1][r]+pm[i-1]+sm[i+1];
cnt[l][r]=cnt[l][i-1]*cnt[i+1][r]*C(r-l,i-l);
}
else if(dp[l][r]==dp[l][i-1]+dp[i+1][r]+pm[i-1]+sm[i+1]){
cnt[l][r]+=cnt[l][i-1]*cnt[i+1][r]*C(r-l,i-l);
}
}
}
}
cout<<cnt[1][n];
fclose(stdin);
fclose(stdout);
return 0;
}
/*
5
2 2 2 1 1
*/
T3
题面
无穷序列
时间限制:1秒 内存限制:256M
题目描述
输入描述
第一行输入一个整数T,表示测试用例的组数。
每组测试用例输入一行包含两个整数n, c。
其中 n 以二进制形式表示,且 n 不含有前导 0
输出描述
对于每组测试用例输出一行一个整数表示答案。
输入样例
5
1001 1
11111 1
101010111101 8999
10100101111010101 799
10010010 233
输出样例
45
496
2835797
707482963
9940
数据描述
初次思路
啊?
复盘思路
啊?
T4
题面
矩阵学说
时间限制:1秒 内存限制:256M
题目描述
给定n行m列的矩阵 ,找出满足以下条件的三元组 (i,j,x) 的数量:
1.1≤i≤n,1≤j≤m,1≤x≤min(n−i+1,m−j+1)
2.矩阵的左上角(i,j) 到右下角)(i+x−1,j+x−1) 恰好含有k个不同的整数。
输入描述
第一行输入三个整数n,m,k。
接下来输入一个 n*m 的矩阵,表示 ai,j
输出描述
输出一行一个整数表示答案。
输入样例
2 3 4
1 2 3
4 5 6
输出样例
2
样例说明
满足条件的三元组有: (1,1,2),(1,2,2)。
数据描述
初次思路
异或前缀!!!!!!!!!!!!!!!!!!!!!!!!!!!!
不会写!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
很重要!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
等着学!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
复盘思路
二维ST表(看题解)