H - Local Minimum(签到)
https://codeforces.com/gym/103447/problem/J
题意:
给一个矩阵,问 有多少个元素满足:既是当前行的最小值,又是当前列的最小值
思路:
用两个数组维护每一行每一列最小值,n*m 遍历判断即可
样例:
3 3 1 5 9 4 3 7 2 6 2
3
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e3+5;
int a[N][N];
int mn1[N],mn2[N];
void solve(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)mn1[i]=INT_MAX;
for(int i=1;i<=m;i++)mn2[i]=INT_MAX;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
mn1[i]=min(mn1[i],a[i][j]);
mn2[j]=min(mn2[j],a[i][j]);
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==mn1[i]&&a[i][j]==mn2[j])ans++;
}
}
cout<<ans<<endl;
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
while(T--){
solve();
}
return 0;
}
E - Shinyruo and KFC
https://codeforces.com/gym/103428/problem/G
题意:
有 n 种食品,每种食品有 a [ i ] 个,有 k 个人,每个人每种食品 最多拿一个,可以拿多种,求把所有食品分配完的方案数,当 k 取 1到m 时,分别输出答案
思路:
问题可以转化为,n项 C ( k , a [ i ] ) 的乘积
发现对于某个 a[i] ,对答案的贡献是一定的,开个map,记录下 每个数量对应的食品个数,通过快速幂求解
代码:
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
#define int long long
const int N=1e5+5;
int mod=998244353;
int fact[N],inv[N]; //O(1)求组合数
int qpow(int a,int b){
int ans=1;
while(b>0){
if(b&1)
ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
void Cinit(){
fact[0]=1,inv[0]=1;
for(int i=1;i<=N-1;i++){
fact[i]=fact[i-1]*i%mod;
//inv[i]=inv[i-1]*qpow(i,mod-2)%mod;
}
inv[N-1]=qpow(fact[N-1],mod-2)%mod;
for(int i=N-2;i>=1;i--){
inv[i]=inv[i+1]*(i+1)%mod;
}
}
int C(int a,int b){
if(a<0||b<0||a<b)return 0;
return fact[a]*inv[a-b]%mod*inv[b]%mod;
}
int a[N];
void solve(){
Cinit();
int n,m;
cin>>n>>m;
int mx=0;
map<int,int>mp;
for(int i=1;i<=n;i++){
cin>>a[i];
if(mp.find(a[i])==mp.end())mp[a[i]]=1;
else mp[a[i]]++;
mx=max(mx,a[i]);
}
sort(a+1,a+1+n);
int tmp=min(m,mx-1);
for(int i=1;i<=tmp;i++){
cout<<0<<endl;
}
for(int i=tmp+1;i<=m;i++){
int ans=1;
for(auto j:mp){
ans*=qpow(C(i,j.first),j.second);
ans%=mod;
}
cout<<ans<<endl;
}
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
//cin>>T;
while(T--){
solve();
}
return 0;
}
F - Pudding Store
题意:
构造一个排列,使得 前 i 项的和*2 是 i 的倍数,求排列的个数
思路:
限制条件不好处理,直接打表看看有没规律,发现是3*2^(n-3)
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[105];
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++)a[i]=i;
int ans=0;
do{
int tmp=0;
ans++;
for(int i=1;i<=n;i++){
tmp+=2*a[i];
if(tmp%i!=0){
ans--;
break;
}
}
}while(next_permutation(a+1,a+1+n));
cout<<ans<<endl;
return;
}
signed main(){
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
I - Magical Subsequence
题意:
给一个长为 n 的序列,每一项不超过100,存在子序列满足 对所有k为奇数,第k项+第k+1项相等,求这个序列最长长度
思路:
枚举第k项和第k+1项的和,然后遍历序列,用 vis 记录扫过的可以取的值,queue将全部清空操作优化为 O(n),如果可以组成一个和,就清空queue
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<" = "<<x<<endl;
using namespace std;
#define int long long
const int N=1e5+5;
int a[N],vis[205];
void solve(){
int n;
cin>>n;
int mx=1;
for(int i=1;i<=n;i++){
cin>>a[i];
mx=max(mx,a[i]);
}
int ans=0;
for(int aim=2;aim<=2*mx;aim++){
int len=0;
queue<int>q;
for(int i=1;i<=n;i++){
if(a[i]>=aim)continue;
int tmp=aim-a[i];
if(vis[tmp]){
len+=2;
while(!q.empty()){
vis[q.front()]=0;
q.pop();
}
}
else{
if(vis[a[i]])continue;
q.push(a[i]);
vis[a[i]]=1;
}
}
while(!q.empty()){
vis[q.front()]=0;
q.pop();
}
ans=max(ans,len);
}
cout<<ans<<endl;
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
//cin>>T;
while(T--){
solve();
}
return 0;
}
A - Sergey and Subway
https://www.luogu.com.cn/problem/CF1060E
题意:
给一颗树,给所有距离为2的点对 建一条新边,求新图上 所有两点间距离的和
思路:
考虑原图上两点u,v,在新图上 一次可以走原图的两步,如果dis(u,v) 是偶数,新距离为dis/2,如果dis(u,v)为奇数,新距离为(dis+1)/2
合并所有答案 ans=(原图上所有点对dis的和 + 原图上dis为奇数的点对数量)/2
前者我们通过枚举每条边的贡献,在一遍dfs中处理出来,后者我们可以将原树奇偶分层,距离为奇数的两点一定在奇偶不同的两层,计算出两层的点数,相乘即是点对的数量
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int head[N],cntt=0;
struct Edge{
int to,next;
}edge[2*N];
void add(int u,int v){
edge[++cntt].to=v;
edge[cntt].next=head[u];
head[u]=cntt;
}
int n,siz[N],ans,cnt[2],flag[N];
void dfs(int x,int f){
cnt[flag[x]]++; //统计奇偶层的点数
siz[x]=1;
for(int i=head[x];i;i=edge[i].next){
int y=edge[i].to;
if(y==f)continue;
flag[y]=flag[x]^1;
dfs(y,x);
siz[x]+=siz[y];
ans+=(n-siz[y])*siz[y]; //计算每条边的贡献
}
}
void solve(){
cin>>n;
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs(1,1);
ans+=cnt[0]*cnt[1];
cout<<ans/2<<endl;
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
while(T--){
solve();
}
return 0;
}