因为本蒟蒻错过了这场比赛,所以赶紧回来打模拟赛……
思路
直接模拟即可,但是要细心!
时间复杂度: O ( n + q ) O(n+q) O(n+q)
预估难度:入门/普及-
代码
#include
#define int long long
using namespace std;
int n,q,temp,p=0,c=0;
int a[100005],b[100005];
signed main()
{
cin>>n>>q;
for (int i=1;i<=q;i++)
{
string s;
cin>>temp>>s;
if (s=="AC") a[temp]=1;
else
{
if (a[temp]==0) b[temp]++;
}
}
for (int i=1;i<=n;i++)
{
if (a[i])
{
c++;
p+=b[i];
}
}
cout<<c<<' '<<p<<endl;
return 0;
}
思路
初看题目,发现是个图论题?! 千万不能挂掉啊~
我们先开一个四维数组GA,其中 G A [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] GA[x1][y1][x2][y2] GA[x1][y1][x2][y2]储存了坐标 ( x 1 , y 1 ) (x1,y1) (x1,y1)到 ( x 2 , y 2 ) (x2,y2) (x2,y2)的距离。接着我们找两个相邻(行相邻或列相邻)的"."并记录该两点的距离为 1 1 1。然后跑一遍弗雷德( F l o y d Floyd Floyd),最后扫一遍找到最长的最短距离即可。
注意初始化!
时间复杂度: O O O( h 3 h^3 h3 w 3 w^3 w3)
预估难度: 普及/提高-
代码
#include
#define inf 1000000007
using namespace std;
int n,m,maxv=-1;
char a[25][25];
int GA[25][25][25][25];
int main()
{
cin>>n>>m;
memset(a,' ',sizeof(a));
memset(GA,inf,sizeof(GA));
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) cin>>a[i][j];
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
if (a[i][j]==a[i][j-1]&&a[i][j]=='.') GA[i][j][i][j-1]=GA[i][j-1][i][j]=1;
if (a[i][j]==a[i][j+1]&&a[i][j]=='.') GA[i][j][i][j+1]=GA[i][j+1][i][j]=1;
if (a[i][j]==a[i+1][j]&&a[i][j]=='.') GA[i][j][i+1][j]=GA[i+1][j][i][j]=1;
if (a[i][j]==a[i-1][j]&&a[i][j]=='.') GA[i][j][i-1][j]=GA[i-1][j][i][j]=1;
}
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) GA[i][j][i][j]=0;
}
for (int ki=1;ki<=n;ki++)
{
for (int kj=1;kj<=m;kj++)
{
if (a[ki][kj]=='#') continue;
for (int ii=1;ii<=n;ii++)
{
for (int ij=1;ij<=m;ij++)
{
if (a[ii][ij]=='#') continue;
for (int ji=1;ji<=n;ji++)
{
for (int jj=1;jj<=m;jj++)
{
if (a[ji][jj]=='#') continue;
if (GA[ii][ij][ji][jj]>GA[ii][ij][ki][kj]+GA[ki][kj][ji][jj])
{
GA[ii][ij][ji][jj]=GA[ii][ij][ki][kj]+GA[ki][kj][ji][jj];
GA[ji][jj][ii][ij]=GA[ii][ij][ki][kj]+GA[ki][kj][ji][jj];
}
}
}
}
}
}
}
for (int ii=1;ii<=n;ii++)
{
for (int ij=1;ij<=m;ij++)
{
for (int ji=1;ji<=n;ji++)
{
for (int jj=1;jj<=m;jj++)
{
if (GA[ii][ij][ji][jj]>n*m) continue;
else maxv=max(maxv,GA[ii][ij][ji][jj]);
}
}
}
}
cout<<maxv<<endl;
return 0;
}
前言
这是一道不错的数学题,欢迎大家前来拍砖。
思路
对于这类题目有一种套路: 求贡献之和。
但是我们怎么知道这个数对答案的贡献呢?我们只需要将它按升序排序后做一些神仙操作 :
①把第i个数与前面的k-1个数相结合,那么他就成为了最大值;所以它给答案的贡献为 a i × C ( i − 1 , k − 1 ) ai×C(i-1,k-1) ai×C(i−1,k−1)。注意这里 C ( i − 1 , k − 1 ) C(i-1,k-1) C(i−1,k−1)表示在第i个数前面的i-1个数中选k-1个数的方案数。
②把第i个数与后面的k-1个数相结合,那么他就成为了最小值;所以它给答案的贡献为- a i ∗ C ( n − i , k − 1 ) ai*C(n-i,k-1) ai∗C(n−i,k−1)。注意这里 C ( n − i , k − 1 ) C(n-i,k-1) C(n−i,k−1)表示在第i个数后面的n-i个数中选k-1个数的方案数。
综上所述,答案就是
Σ ( i = 1 , n ) Σ(i=1,n) Σ(i=1,n) a i ( C ( i − 1 , k − 1 ) − C ( n − i , k − 1 ) ) ai(C(i-1,k-1)-C(n-i,k-1)) ai(C(i−1,k−1)−C(n−i,k−1))
//本蒟蒻不会LaTeX数学公式,请见谅
时间复杂度: O ( n ) O(n) O(n)
预估难度: 普及+/提高
卡点
①看到组合数与模数了吗?所以要用逆元(相信大家都用得很熟了吧);
②开long long。有模数就不用开long long,这话您听谁说的?
代码
#include
#define int long long
using namespace std;
int n,k,mod=1e9+7,ans;
int a[100005],jc[100005];
int quick_power(int a,int b)
{
int res=1;
for (;b;b=b>>1,a=(a*a)%mod)
{
if (b&1) res=(res*a)%mod;
}
return res;
}
int ny(int k)
{
return quick_power(k,mod-2);
}
int C(int n,int k)
{
if (n<=0||k<0||n<k) return 0;
if (n==k||k==0) return 1;
if (2*k>n) k=n-k;
return ((jc[n]*ny(jc[n-k]))%mod*ny(jc[k]))%mod;
}
int init()
{
jc[0]=1;
for (int i=1;i<=100000;i++) jc[i]=(jc[i-1]*i)%mod;
}
signed main()
{
cin>>n>>k;
init();
for (int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
for (int i=1;i<=n;i++) ans=((ans+a[i]*(C(i-1,k-1)-C(n-i,k-1)))%mod+mod)%mod;
cout<<ans<<endl;
return 0;
}
本蒟蒻先后使用暴力, 凸包, 二分给尝试了一波,结果都在编完后检查时均把思路否认了o(╥﹏╥)o……
待填坑……
①AC题数: 5(本蒟蒻水平也就这样……)
②5题AC耗时: 1+3+12+30+18=64min
今天晚上还有一场ABC……不管了,打ヾ(◍°∇°◍)ノ゙!!!