A - 无线网络整点栅格统计
题目链接
算法:模拟
题目大意
给你一个n*m的网格,然后输出每一个点作为顶点能构成的正方形数量(可以为斜正方形).
算法思路
本身题目数据是很小的,可以通过n^2的时间复杂度枚举每一个顶点,然后再通过n平方的时间复杂度枚举出另一个对角顶点,判断剩下的两个点是否在网格里面即可.这样的话时间复杂度是n的四次方时间复杂度了,可以通过.
我们可以知道当以A为顶点的斜正方形一定可以被过A的正正方形包围,那么我们每个店只需要求出过这个点所能构成的正正方形数量即可.
至于如何求每个点构成的正正方形数量可以根据个人理解来求.
我的思路是:我们可以通过记录A点左边,上边,斜左上角,本身的正正方形数量,然后这样过A点的正正方形数量就是四个之和.
代码
#include<bits/stdc++.h>
#define ll long long
const int N = 1e5+7;
int dx[]= {1,-1,0,0,1,1,-1,-1};
int dy[]= {0,0,1,-1,1,-1,1,-1};
using namespace std;
struct Node {
//自身 左边 上边
//左上角
int ct,lt,fr;
int lf;
};
Node a[107][107];
int n,m;
int ce(int x,int y) {
return min(n+1-x,m+1-y);
}
int celf(int x,int y) {
return min(x-1,m+1-1)*min(y-1,n+1-1);
}
int ti[107][107];
int tj[107][107];
void slove() {
for(int i=1; i<=100; ++i) {
ti[0][i]=-2;
tj[i][0]=-2;
}
cin>>n>>m;
for(int i=1; i<=(ll)ceil(1.0*(n+1)/2); ++i) {
for(int j=1; j<=(ll)ceil(1.0*(m+1)/2); ++j) {
a[i][j].ct=ce(i,j);
if(i<=m+1) {
ti[i][j]=ti[i-1][j]+1;
if(i!=1) a[i][j].fr=a[i-1][j].ct+max(0,(a[i-1][j].fr+-ti[i][j]));
} else {
//需要去掉刚好到i-1的情况
a[i][j].fr=a[i-1][j].fr;
}
if(j<=n+1) {
tj[i][j]=tj[i][j-1]+1;
if(j!=1) a[i][j].lt=a[i][j-1].ct+max(0,(a[i][j-1].lt+-tj[i][j]));
} else {
//需要去掉刚好到j-1的情况
a[i][j].lt=a[i][j-1].lt;
}
a[i][j].lf=celf(i,j);
}
}
for(int i=1; i<=(ll)ceil(1.0*(n+1)/2); ++i) {
for(int j=1; j<=(ll)ceil(1.0*(m+1)/2); ++j) {
cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
}
if((m+1)%2==0) {
for(int j=(ll)ceil(1.0*(m+1)/2); j>=1; --j) {
cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
}
} else {
for(int j=(ll)ceil(1.0*(m+1)/2)-1; j>=1; --j) {
cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
}
}
cout<<endl;
}
if((n+1)%2==0) {
for(int i=(ll)ceil(1.0*(n+1)/2); i>=1; --i) {
for(int j=1; j<=(ll)ceil(1.0*(m+1)/2); ++j) {
cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
}
if((m+1)%2==0) {
for(int j=(ll)ceil(1.0*(m+1)/2); j>=1; --j) {
cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
}
} else {
for(int j=(ll)ceil(1.0*(m+1)/2)-1; j>=1; --j) {
cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
}
}
cout<<endl;
}
} else {
for(int i=(ll)ceil(1.0*(n+1)/2)-1; i>=1; --i) {
for(int j=1; j<=(ll)ceil(1.0*(m+1)/2); ++j) {
cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
}
if((m+1)%2==0) {
for(int j=(ll)ceil(1.0*(m+1)/2); j>=1; --j) {
cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
}
} else {
for(int j=(ll)ceil(1.0*(m+1)/2)-1; j>=1; --j) {
cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
}
}
cout<<endl;
}
}
return;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin>>t;
while(t--) {
slove();
cout<<endl;
}
return 0;
}
C. Liar
题目链接
算法:思维
题目大意
有n个数,这些个数的总和为s,这些数有真有假,输出最多有多少个数是真的
算法思路
因为当这个数为假的时候,我们可以把这个数设为无穷数,那么当n个数都为真无法满足总和为s的情况,我们可以让前n-1个数都为真,然后通过最后一个数进行调节,满足n个数的总和为s的情况
代码
#include<bits/stdc++.h>
#define ll long long
const int N = 1e5+7;
int dx[]= {1,-1,0,0,1,1,-1,-1};
int dy[]= {0,0,1,-1,1,-1,1,-1};
using namespace std;
ll a[N];
void slove() {
ll n,s;
cin>>n>>s;
for(int i=1; i<=n; ++i) cin>>a[i];
sort(a+1,a+n+1);
ll ans = 0;
for(int i=1; i<=n; ++i) {
ans+=a[i];
}
if(ans==s) {
cout<<n;
return;
}
cout<<n-1;
}
int main() {
int t = 1;
// cin>>t;
while(t--) {
slove();
cout<<endl;
}
return 0;
}
Magic LCM
题目链接
算法:数学+模拟+贪心
题目大意
给你一个长度为n的数组,然后你可以进行无数次操作:选择两个不同的数(x,y),设x为gcd(x,y),y为lcm(x,y).
求出最后这个数组之和的最大值.
算法思路
对于两个数进行gcd和lcm赋值,其实gcd就是公共因子,lcm就是公共因子不同的因子.
而且因子和因子之间互不打扰.
那么我们就可以把数组里面的每一个数进行拆解,拆解成质因子,依次求出进行操作以后的最大值.
又因为操作就是将公共因子乘不同的因子,那么我们可以让质因子个数多的先提供,求出一个当前的最大值.
比如:9 6 4 27 10 12这个数组
9->33
6->23
4->22
27->333
10->25
12->223
那么我们可以先让4提供两个2,27提供三个3,10提供一个5,这样组成540.
剩下的数
33
23
2
22*3
注意,质因子之间相互独立,所以不用在意是具体是谁提供的
我们继续两个2,两个3组成36
一个2.一个3
组成6
一个2.一个3
组成6
这样把所有的质因子都用掉以后
还剩下两个数,这两个数就是1
#include<bits/stdc++.h>
#define ll long long
const int N = 1e6+7;
const int M = 998244353;
int dx[]= {1,-1,0,0,1,1,-1,-1};
int dy[]= {0,0,1,-1,1,-1,1,-1};
using namespace std;
struct Node {
map<int,ll> mp;
set<int> st;
};
Node a[N];
priority_queue<ll, vector<ll>, less<ll>> q[N];
set<int> tst;
ll q_pow(ll n,ll x) {
ll sum=1;
while(x) {
if(x&1) sum*=n;
x>>=1;
n*=n;
n%=M;
sum%=M;
}
sum%=M;
return sum;
}
void slove() {
ll n;
cin>>n;
for(int i=1,t; i<=n; ++i) {
cin>>t;
for(auto &v:a[t].st) {
tst.insert(v);
q[v].push(a[t].mp[v]);
}
}
ll ans = 0;
int sz = 0;
int flag = 0;
while(1) {
flag = 0;
ll tans = 1;
for(auto it = tst.begin(); it != tst.end();) {
if(q[*it].empty()) {
it = tst.erase(it);
} else {
flag = 1;
ll t = q_pow(*it,q[*it].top());
q[*it].pop();
tans*=t;
tans%=M;
++it;
}
}
ans += tans;
ans%=M;
sz++;
if(flag == 0) break;
}
cout<<ans+n-sz;
return;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
a[1].mp[1]=1;
for(int i=2; i<=1e6; ++i) {
int flag = 0;
for(int j=2; j*j<=i; ++j) {
if(i%j==0) {
flag = 1;
int t = i/j;
for(auto &v:a[t].st) {
a[i].mp[v]+=a[t].mp[v];
a[i].st.insert(v);
}
a[i].mp[j]++;
a[i].st.insert(j);
break;
}
}
if(flag == 0) {
a[i].mp[i]++;
a[i].st.insert(i);
}
}
// int mx = 0;
// for(int i=1;i<=1e6;++i) {
// mx = max(mx,(int)a[i].st.size());
// }
// cout<<mx;
int t = 1;
cin>>t;
while(t--) {
slove();
cout<<endl;
}
return 0;
}
这个代码部分main里面对如何在nlogn的时间复杂度求出1-n里面每个数分别有哪些因子可以重点看一下.