A.思维
可以搜索
但是根据题目所给的移动条件,我们可以推断
只要从第一列到最后一列之间不存在同一列两行都为陷阱的情况
我们就一定可以到达
#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
char g[110][3];
int main()
{
ios::sync_with_stdio(0);
int T;cin>>T;
while (T--)
{
int n;cin>>n;
for (int i=1;i<=n;++i)cin>>g[i][1];
for (int i=1;i<=n;++i)cin>>g[i][2];
string s = "YES\n";
for (int i=1;i<=n;++i)if (g[i][1]==g[i][2]&&g[i][1]=='1')
{
s = "NO\n";
break;
}
cout<<s;
}
}
B.暴力
我们可以暴力枚举在第一、二两组在哪两天开会
day1,day2day_1,day_2day1,day2
然后,判断nnn个人能否均分为两组
- 如果有人day1,day2day_1,day_2day1,day2都没空,显然不可以
- 只在day1day_1day1有空的人和只在day2day_2day2有空的人不能超过n2\frac n22n
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1100;
int can[maxn][5];
int n;
void solve()
{
for (int day1 = 0;day1<5;++day1)
for (int day2 = day1+1;day2<5;++day2)
{
int cnt1 = 0,cnt2 = 0,cnt3 = 0;
for (int i=1;i<=n;++i)
{
if (can[i][day1]&&can[i][day2])++cnt3;
else if (can[i][day1])++cnt1;
else if (can[i][day2])++cnt2;
}
if (cnt1+cnt2+cnt3!=n)continue;
if (cnt1*2<=n&&cnt2*2<=n)
{
cout<<"YES\n";
return;
}
}
cout<<"NO\n";
}
int main()
{
ios::sync_with_stdio(0);
int T;cin>>T;
while (T--)
{
cin>>n;
for (int i=1;i<=n;++i)
for (int j=0;j<5;++j)cin>>can[i][j];
solve();
}
}
C.模拟
统计就好了
如果我们已经知道了平均数aveaveave
那么我们可以枚举所有的数aia_iai,根据平均数计算出aja_jaj值,加上aja_jaj出现的个数即可
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+100;
typedef long long ll;
int a[maxn];
int n;
map<int,int> mp;
int main()
{
ios::sync_with_stdio(0);
int T;cin>>T;
while (T--)
{
cin>>n;ll sum = 0;mp.clear();
for (int i=1;i<=n;++i)cin>>a[i];
for (int i=1;i<=n;++i)sum += a[i];
if (sum*2LL%n!=0)
{
cout<<"0\n";
continue;
}sum = sum*2LL/n;
ll ans = 0;
for (int i=1;i<=n;++i)
{
if (mp.count(sum-a[i]))ans+=mp[sum-a[i]];
mp[a[i]]++;
}cout<<ans<<"\n";
}
}
D.思维+计数
数据量只支持O(n)O(n)O(n)或者O(nlogn)O(nlogn)O(nlogn)的解法
我们观察题目所给的特殊的限制条件!
- 不存在一个点对(i,j)(i,j)(i,j)使得ai==aja_i==a_jai==aj且bi==bjb_i==b_jbi==bj
- 满足条件的要求是ai≠aj≠ak∣∣bi≠bj≠bka_i\not=a_j\not=a_k||b_i\not=b_j\not=b_kai=aj=ak∣∣bi=bj=bk
首先我们根据第一个条件,可以把所有点投射到一个2e5∗2e52e5*2e52e5∗2e5的矩阵上
行坐标为aia_iai,纵坐标为bib_ibi
因为条件一,所以每一个坐标点上最多只有一个点
再根据条件二,思考一会发现直接求解是困难的
考虑容斥
什么情况下,不满足条件二呢?
选取的三个点中,至少有两个点在同一行,且至少有两个在同一列
投射到矩阵上就是下面四种情况:




我们计算每一行,每一列有多少个点,然后枚举每一个点作为中间节点,计算有多少种情况
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+100;
typedef long long ll;
int row[maxn],col[maxn];
int a[maxn],b[maxn];
int n;
int main()
{
ios::sync_with_stdio(0);
int T;cin>>T;
while (T--)
{
cin>>n;
for (int i=1;i<=n;++i)
{
cin>>a[i]>>b[i];
row[a[i]]++;
col[b[i]]++;
}
ll ans = 1LL*n*(n-1)*(n-2)/6LL;
for (int i=1;i<=n;++i)
ans -= 1LL*(row[a[i]]-1)*(col[b[i]]-1);
cout<<ans<<"\n";
for (int i=1;i<=n;++i)
{
--row[a[i]];
--col[b[i]];
}
}
}
E.dpdpdp+思维
如果没有翻转的操作,单纯询问n×mn\times mn×m的矩阵中有多少个楼梯
我们利用dpdpdp计算
dp[0][i][j],dp[1][i][j]:dp[0][i][j],dp[1][i][j]:dp[0][i][j],dp[1][i][j]:分别是以(i,j)(i,j)(i,j)为结尾的两种不同的楼梯个数
并且我们把只取自身(i,j)(i,j)(i,j)既看做成第一种也看做成第二种
dp[0][i][j]=dp[1][i−1][j]+1dp[0][i][j]=dp[1][i-1][j]+1dp[0][i][j]=dp[1][i−1][j]+1
dp[1][i][j]=dp[0][i][j−1]+1dp[1][i][j]=dp[0][i][j-1]+1dp[1][i][j]=dp[0][i][j−1]+1
最终统计以每一点为结尾的楼梯的个数
即−n×m+∑(i,j)dp[0][i][j]+dp[1][i][j]-n\times m+\sum_{(i,j)}dp[0][i][j]+dp[1][i][j]−n×m+∑(i,j)dp[0][i][j]+dp[1][i][j]
利用cntcntcnt记录矩阵中freefreefree状态的点,初始free=n×mfree=n\times mfree=n×m
当我们改动点(x,y)(x,y)(x,y)时,dp[1][x][y],dp[0][x][y],cntdp[1][x][y],dp[0][x][y],cntdp[1][x][y],dp[0][x][y],cnt均发生改变
当dp[0][x][y]dp[0][x][y]dp[0][x][y]改变时,dp[1][i][j+1]dp[1][i][j+1]dp[1][i][j+1]也改变
当dp[1][x][y]dp[1][x][y]dp[1][x][y]改变时,dp[0][i+1][j]dp[0][i+1][j]dp[0][i+1][j]也改变
如此,我们一路更新dpdpdp的状态,会发现,至多更新O(n)O(n)O(n)
因此,暴力更新dpdpdp状态,维护dpdpdp数组的和与cntcntcnt
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1100;
typedef long long ll;
ll dp[2][maxn][maxn];
int g[maxn][maxn];
int n,m,q;
ll ans = 0;
void dfs(int x,int y,int sta)
{
if (x>n||y>m)return;
ans-=dp[sta][x][y];
if (g[x][y]==1)dp[sta][x][y]=0;
else if (sta==0)dp[sta][x][y] = dp[sta^1][x-1][y]+1;
else dp[sta][x][y] = dp[sta^1][x][y-1]+1;
ans+=dp[sta][x][y];
if (sta==0)dfs(x,y+1,sta^1);
else dfs(x+1,y,sta^1);
}
int main()
{
ios::sync_with_stdio(0);
cin>>n>>m>>q;
for (int i=1;i<=n;++i)
{
for (int j=1;j<=m;++j)
{
dp[0][i][j]=dp[1][i-1][j]+1;
dp[1][i][j]=dp[0][i][j-1]+1;
ans+=dp[0][i][j]+dp[1][i][j];
}
}
int cnt = n*m;
while (q--)
{
int x,y;cin>>x>>y;
if (g[x][y])++cnt;
else --cnt;
g[x][y]^=1;
dfs(x,y,0);
dfs(x,y,1);
cout<<ans-cnt<<"\n";
}
}
本文通过五个实例展示了不同类型的算法问题解决方案,包括基于移动条件的路径判断、会议安排、统计计算、二维平面上点的排列以及矩阵中楼梯计数。涉及到了暴力枚举、模拟统计、动态规划等思维和计数技巧,揭示了在解决信息技术问题时的多种策略。
1277

被折叠的 条评论
为什么被折叠?



