题意:有两个矩阵,问是否可以把第一个矩阵进行行列两种变化变成第二个矩阵
思路:我的想法是把第一个矩阵扩展成四个,也就有点类似于化圆为线的思想,然后循环每一种可能性,与目标比较,但是错了,不知道为什么?
题解:直接通过四重循环,因为h,w小于30
前两重循环两种操作的次数,通过a[(i-s+H)%H][(j-t+W)%W]==B[i][j]判断
for(int s=0;s<H;s++)
for(int t=0;t<W;t++)
{
int ok=0;
for(int i=0;i<H;i++)
for(int j=0;j<W;j++)
if(A[(i-s+H)%H][(j-t+W)%W]!=B[i][j])ok=0;
}
题意:有多少个小于N的数字可以被三个质数用a*a*b*c*c来表示
思路 :首先根据N范围可以直到c<=288675,因此我们需要准备好一个大小P=25997的数组
如何不重不漏?i:from 1 to P
j:from i+1 to P
k=P k-- while:j<k<P 质数i*i *j*k*k>N
k'=k 那么ans+=k-j
思想:首先要做到不重不漏,就得保证一定的顺序,i j保证了顺序,在此基础上寻找答案,因为要求的是个数,所以找到极限位置是最重要的,那么就从边界逼近,也就是k的操作,然后相减就可以得到数目的答案
tiptiptip:
初始化的init放在main里面,栈区域小啊啊啊
循环里面及时break
寻找j用二分,先把所有的平方给预处理到数组里面,然后用lower_bound,(while不对啊
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define int long long
using namespace std;
const int N=1e7+10;
int st[N];
int primes[N];
vector<bool>prime(N,true);
vector<int>p;
int cnt;
int ans;
int n;
void init()
{/*
for(int i=2;i<=n;i++)
{
if(!st[i])
{
primes[cnt++]=i;
}
for(int j=0;primes[j]*i<=n;j++)
{
st[primes[j]*i]=1;
if(i%primes[j]==0)break;
}
}*/
for(int i=2;i<=N;i++)
{
if(prime[i])
{
p.push_back(i);
for(int j=i*2;j<=N;j+=i)
{
prime[j]=false;
}
}
}
}
signed main()
{
cin>>n;
for(int i=2;i<=N;i++)
{
if(prime[i])
{
p.push_back(i);
for(int j=i*2;j<=N;j+=i)
{
prime[j]=false;
}
}
}
cnt=p.size();
vector<long long>pp(cnt);
for(int i=0;i<cnt;i++)
{
pp[i]=(long long)p[i]*p[i];
}
for(int i=0;i<cnt;i++)
{
int a=p[i];
if(a*a*a*a*a>n)break;
for(int j=i+1;j<cnt;j++)
{
int b=p[j];
if(a*a*b*b*b>n)break;
/* int k=cnt-1;
while(k>=j&&a*a*b*primes[k]*primes[k]>n)
{
k--;
}
ans+=k-j;*/
auto itr=upper_bound(pp.begin()+j+1,pp.end(),n/a/a/b);
ans+=itr-(pp.begin()+j+1);
// cout<<a*a*b*primes[k]*primes[k]<<endl;
}
}
cout<<ans<<endl;
}
题意: 你有一个色子,六种可能性相同,然后每次乘以你掷出来的,你能最后到达N的几率
这是一个概率dp:
思路:把我们的目标分解成出 2,3,5的幂次方
进行dp,目标是【0】【0】【0】,每一次*1/5
注意!!!
X*5 =1(mod 888244353) X=1/5----> 598946612
#include <bits/stdc++.h>
using namespace std;
const long long MOD = 998244353;
const long long ONE_FIFTH = 598946612;
int main(){
long long N;
cin >> N;
long long a = 0, b = 0, c = 0;
while (N % 2 == 0){
N /= 2;
a++;
}
while (N % 3 == 0){
N /= 3;
b++;
}
while (N % 5 == 0){
N /= 5;
c++;
}
if (N != 1){
cout << 0 << endl;
} else {
vector<vector<vector<long long>>> dp(a + 1, vector<vector<long long>>(b + 1, vector<long long>(c + 1, 0)));
dp[a][b][c] = 1;
for (int i = a; i >= 0; i--){
for (int j = b; j >= 0; j--){
for (int k = c; k >= 0; k--){
if (!(i == a && j == b && k == c)){
if (i + 1 <= a){
dp[i][j][k] += dp[i + 1][j][k];
}
if (j + 1 <= b){
dp[i][j][k] += dp[i][j + 1][k];
}
if (i + 2 <= a){
dp[i][j][k] += dp[i + 2][j][k];
}
if (k + 1 <= c){
dp[i][j][k] += dp[i][j][k + 1];
}
if (i + 1 <= a && j + 1 <= b){
dp[i][j][k] += dp[i + 1][j + 1][k];
}
dp[i][j][k] %= MOD;
dp[i][j][k] *= ONE_FIFTH;
dp[i][j][k] %= MOD;
}
}
}
}
cout << dp[0][0][0] << endl;
}
}
题意:k-smooth数: 如果将一个数分解质因数,没有一个质数超过k
现在给一个N和质数P,请找到所有不超过N的p-smooth的个数
思路:这个N太大了,所以要寻找可以考虑分成两个部分,然后在合起来,用二分查找来降低时间复杂度,还挺常见一个思想
先对于每个质数进行收集,然后对于其中一个数组进行遍历,遍历的时候去查询,双指针的j往前面走,然后每次res+=j+1;
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
void step(vector<long long> &a,long long p,long long mxm)
{
long long sz=a.size();
for(long long i=0;i<sz;i++)
{
long long ad=a[i];
while(1)
{
ad*=p;
if(ad>mxm)break;
a.push_back(ad);
}
}
}
int main()
{
vector<long long> pl={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
long long n,p;
cin >> n >> p;
while(p<pl.back()){pl.pop_back();}
vector<long long>u={1},v={1};
for(auto &nx:pl)
{
if(u.size()<v.size()){
step(u,nx,n);
}
else step(v,nx,n);
}
sort(u.begin(),u.end());
sort(v.begin(),v.end());
long long res=0,j=v.size()-1;
for(long long i=0;i<u.size();i++)
{
long long mv=(n/u[i]);
while(j>=0&&mv<v[j]){j--;
}
if(j<0)break;
res+=(j+1);
}
cout<<res<<endl;
return 0;
}