分析:这题需要分3种情况来讨论。
2条边都与坐标轴平行的三角形
一定存在于
或者
的矩形中,每个当中存在4个,则只需要统计矩形的数量即可
底与坐标轴平行的三角形,且底为2
底与坐标轴平行的三角形,且底为1
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
LL n,m;
int main()
{
cin>>n>>m;
LL sum=0;
sum=(sum+(4ll*(n-1)*(m-2)%mod+(4ll*(m-1)*(n-2)%mod))%mod)%mod;
sum=(sum+((2ll*(m-1)*(n-2)%mod*(n-2)%mod)%mod+(2ll*(n-1)*(m-2)%mod*(m-2)%mod)%mod)%mod)%mod;
sum=(sum+((2ll*(m-2)*(n-1)%mod*(n-2)%mod)%mod+(2ll*(n-2)*(m-1)%mod*(m-2)%mod)%mod)%mod)%mod;
cout<<sum<<endl;
return 0;
} #include "bits/stdc++.h"
using namespace std;
int n,x,a,b;
int main()
{
scanf("%d%d%d%d",&n,&x,&a,&b);
int tmp=n*(x*a+((100-x)*b));
printf("%.2f\n",(double)tmp/100.0);
return 0;
} 分析:首先如果在同一象限内的,隔板无法分开。如果处于不同象限,我们则分别求出每个点与X轴和与Y轴的交点,然后使得挡板能够挡住n-k个点即可,于是可以通过双指针来求min值
#include "bits/stdc++.h"
using namespace std;
int n,k;
int main()
{
double x0,y0;
cin>>x0>>y0;
cin>>n>>k;
k=n-k;
vector<double>v1,v2;
for(int i=1;i<=n;i++){
double x,y;
cin>>x>>y;
if(x*x0<0){
v1.push_back(y0-x0*(y-y0)/(x-x0));
}
if(y*y0<0){
v2.push_back(x0-y0*(x-x0)/(y-y0));
}
}
double mi=1e18;
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
if(v1.size()>=k){
int head=0,tail=k-1;
while(tail<v1.size()){
mi=min(mi,v1[tail]-v1[head]);
head++,tail++;
}
}
if(v2.size()>=k){
int head=0,tail=k-1;
while(tail<v2.size()){
mi=min(mi,v2[tail]-v2[head]);
head++,tail++;
}
}
if(mi==1e18) printf("-1\n");
else printf("%.6f\n",mi);
return 0;
} #include "bits/stdc++.h"
using namespace std;
const int maxn=1e5+100;
int n,a[maxn],vis[maxn];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++){
scanf("%d",&a[i]);
vis[a[i]]=1;
}
for(int i=1;i<=n;i++){
if(vis[i]==0){
printf("%d\n",i);
return 0;
}
}
} #include "bits/stdc++.h"
using namespace std;
typedef long long LL;
LL n;
LL solve(LL a){
if(a==2ll) return 2ll;
LL tmp=2;
for(LL i=2;i*i<=a;i++){
if(i*i==a){
tmp++;
}else{
if(a%i==0) tmp+=2;
}
}
return tmp;
}
int main()
{
scanf("%lld",&n);
int cnt=0;
while(n!=2){
cnt++;
n=solve(n);
}
printf("%d\n",cnt);
return 0;
} 分析:如果我们以黑色结点为跟结点节点,则假设它的子树中白色结点数量分别为,则总的方案数为
,化简一下,即为
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=1e5+100;
char s[maxn];
int n;
vector<int>g[maxn];
LL sum;
void dfs(int u,int fa){
if(s[u]=='B') return;
sum++;
for(auto v:g[u]){
if(v!=fa) dfs(v,u);
}
}
int main()
{
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
LL ans=0;
for(int i=1;i<=n;i++){
if(s[i]=='B'){
LL res1=0,res2=0;
for(auto v:g[i]){
sum=0;
dfs(v,v);
ans+=sum;
res1+=sum;
res2+=sum*sum;
}
ans+=(res1*res1-res2)/2;
}
}
printf("%lld\n",ans);
return 0;
} 分析:依次记录每个字母出现的位置,同时维护k个该字母长度的最小值。
#include "bits/stdc++.h"
using namespace std;
const int maxn=27;
vector<int>g[maxn];
int v[maxn];
int n,k;
string s;
int main()
{
cin>>n>>k;
cin>>s;
int len=s.length();
for(int i=0;i<26;i++) v[i]=INT_MAX;
for(int i=0;i<len;i++){
int tmp=s[i]-'a';
g[tmp].push_back(i+1);
if(g[tmp].size()>=k){
int l=g[tmp].size()-1;
int mi=g[tmp][l]-g[tmp][l-k+1]+1;
v[tmp]=min(v[tmp],mi);
}
}
int mx=INT_MAX;
for(int i=0;i<26;i++){
mx=min(mx,v[i]);
}
if(mx==INT_MAX) printf("-1\n");
else printf("%d\n",mx);
return 0;
} 分析:通过维护前缀和来快速维护区间中1和0的数量,然后分别计算把0改为1和把1改为0所能维护的最长序列即可
#include "bits/stdc++.h"
using namespace std;
const int maxn=2e5+100;
int n,k,a[maxn],b[maxn],dp1[maxn],dp2[maxn];
string s;
int main()
{
scanf("%d%d",&n,&k);
cin>>s;
for(int i=1;i<=n;i++){
a[i]=s[i-1]-'0';
b[i]=1-a[i];
dp1[i]=dp1[i-1]+a[i];
dp2[i]=dp2[i-1]+b[i];
}
int l=1,r=1,mx=0;
while(r<=n&&l<=r){
while(dp1[r]-dp1[l-1]<=k&&r<=n) r++;
mx=max(mx,r-l);
//cout<<mx<<endl;
l++;
}
l=1,r=1;
while(r<=n&&l<=r){
while(dp2[r]-dp2[l-1]<=k&&r<=n) r++;
mx=max(mx,r-l);
//cout<<mx<<endl;
l++;
}
printf("%d\n",mx);
return 0;
} 分析:这个是一个比较简单的DP,分别从"nico","niconi","niconiconi" 三个位置转移过来求最大值即可
#include "bits/stdc++.h"
using namespace std;
const int maxn=3e5+10;
typedef long long LL;
int n;
LL a,b,c,dp[maxn];
string s;
int main()
{
cin>>n>>a>>b>>c;
cin>>s;
for(int i=1;i<=n;i++){
dp[i]=dp[i-1];
if(i>=4){
if(s.substr(i-4,4)=="nico") dp[i]=max(dp[i],dp[i-4]+a);
}
if(i>=6){
if(s.substr(i-6,6)=="niconi") dp[i]=max(dp[i],dp[i-6]+b);
}
if(i>=10){
if(s.substr(i-10,10)=="niconiconi") dp[i]=max(dp[i],dp[i-10]+c);
}
}
printf("%lld\n",dp[n]);
return 0;
} 分析:这个题目出得非常有意思,咋一看上去不知道怎么矩阵快速幂,但仔细思考后,发现是可以构造矩阵进行快速幂的。在这里我们应该和
的幂次做矩阵快速幂。我们推一下
出现的次数,可知其实一个前2项为
的斐波拉契数列。同理,我们可以推出
的出现次数是一个前2项为
的斐波拉契数列。我们再做进一步推理可以发现,
的第
项
,就是
的第
项
。同时,
的第n项就是
。最后由于指数比较大,同时右由于
是个素数,所以我们很自然可以想到用费马小定理来进行降幂,即当
为素数时,
。
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
LL n,x,y,a,b;
void mul(LL f[2],LL res[2][2]){
LL c[2];
memset(c,0,sizeof(c));
for(int j=0;j<2;j++){
for(int k=0;k<2;k++)
c[j]=(c[j]+f[k]*res[k][j])%(mod-1);
}
memcpy(f,c,sizeof(c));
}
void mulself(LL res[2][2]){
LL c[2][2];
memset(c,0,sizeof(c));
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
c[i][j]=(c[i][j]+res[i][k]*res[k][j])%(mod-1);
}
}
}
memcpy(res,c,sizeof(c));
}
LL quick(LL a,LL b){
LL res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res%mod;
}
int main()
{
cin>>n>>x>>y>>a>>b;
if(n==1){
cout<<x%mod<<endl;
return 0;
}
if(n==2){
cout<<y%mod<<endl;
return 0;
}
if(x%mod==0||y%mod==0||a%mod==0){
cout<<"0"<<endl;
return 0;
}
x%=mod,y%=mod,a%=mod;
a=quick(a,b);
LL f[2]={1,0};
LL res[2][2]={{0,1},{1,1}};
n--;
for(;n;n>>=1){
if(n&1) mul(f,res);
mulself(res);
}
LL tmp1=quick(x,f[0]);
LL tmp2=quick(y,f[1]);
LL tmp3=quick(a,f[0]+f[1]-1);
cout<<((tmp1*tmp2)%mod*tmp3)%mod<<endl;
return 0;
} 
京公网安备 11010502036488号