------------恢复内容开始------------
A honoka和格点三角形
题解:计算几何加容斥。
先固定一个底边长度为1,那么高度一定为2,固定长度为2,高度一定为1,这样计算出来的好三角形的个数为 (m-1)*m*(n-2)*2+(m-2)*m*(n-1)*2+(n-1)*n*(m-2)*2+(n-2)*n*(m-1)*2。
然后画图可以知道每一个直角三角形都计算了两次,然后在减去直角三角形的个数((m-1)*(n-2)*2+(n-1)*(m-2)*2)*2;
注意计算的时候一定要分开来算,小心爆long long .
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; int main() { ll n,m; cin>>n>>m; ll ans1,ans; // ll ans=(m-1)*m*(n-2)*2+(m-2)*m*(n-1)*2; ll ansa,ansb; ansa=(m-1)*m%mod; ansa=ansa*(n-2)%mod; ansa=ansa*2%mod; ansb=(m-2)*m%mod; ansb=ansb*(n-1)%mod; ansb=ansb*2%mod; ll ans3; ll ans4; // ll ans2=(n-1)*n*(m-2)*2+(n-2)*n*(m-1)*2; ans3=(n-1)*n%mod; ans3=ans3*(m-2)%mod; ans3=ans3*2%mod; ans4=(n-2)*n%mod; ans4=ans4*(m-1)%mod; ans4=ans4*2%mod; ans=(ansa+ansb)%mod; ans=(ans+(ans3+ans4)%mod)%mod; ll sum=((m-1)*(n-2)*2%mod+(n-1)*(m-2)*2%mod)*2%mod; cout<<(ans-sum+mod)%mod<<endl; return 0; }
B kotori和bangdream
这个题目要用double 。不然会爆精度
#include<bits/stdc++.h> using namespace std; int main(){ double n,x,a,b; cin>>n>>x>>a>>b; double x1=x/100.0; double x2=a*x1+b*(1-x1); printf("%.2lf\n",x2*n); return 0; }
C 待补
D hanayo和米饭 签到
E rin和快速迭代
考查质因子分解求因子的个数。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=200; int arr[N]; ll f(ll n){ ll s=1; for(ll i=2;i*i<=n;i++){ if(n%i==0){ ll a=0; while(n%i==0){ n/=i; a++; } s=s*(a+1); } } if(n>1) s=s*2; return s; } int main(){ ll n; cin>>n; ll time=0; ll x=n; while(x!=2){ x=f(x); time++; } cout<<time<<endl; return 0; }
F maki和tree
对树的理解有问题。。。对每一个黑点,我们求出与它直接相连接的白点的连通白点的个数(也可以直接求出每个白点的联通个数)。然后想想看,同一个黑点两个白点如果这两个白点想要相互访问,那么一定会经过该黑点。对同一个黑点连接的两个白点a和b,答案就是a的联通个数乘以b的联通个数,然后在加上a和b的各自的联通个数。
即答案为:
for(int i=0;i<pos;i++){
for(int j=i+1;j<pos;j++)
ans+=dis[i]*dis[j];
ans+=dis[i]
}
由于是相乘,我们可以预处理前缀和,然后可以把复杂度降为o(n)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=1E5+7; char s[N]; vector<ll >ve[N]; ll dis[N]; ll mark[N]; ll arr[N]; ll d[N]; ll bfs(ll x){ queue<ll >que; que.push(x); ll ans=0; while(que.size()){ ll a=que.front(); que.pop(); ans++; mark[a]=x; for(ll i=0;i<ve[a].size();i++){ ll c=ve[a][i]; if(!mark[c]&&s[c]=='W') que.push(c); } } return ans; } int main(){ ll n; cin>>n; scanf("%s",s+1); ll x,y; for(ll i=1;i<=n-1;i++){ cin>>x>>y; ve[x].push_back(y); ve[y].push_back(x); } for(int i=1;i<=n;i++){ if(s[i]=='W'){ if(mark[i]!=0) dis[i]=dis[mark[i]]; else dis[i]=bfs(i); } } ll ans=0; for(ll i=1;i<=n;i++){ if(s[i]=='B'){ ll pos=0; ll sum=0; for(ll j=0;j<ve[i].size();j++){ if(s[ve[i][j]]=='W'){ arr[pos++]=ve[i][j]; } } d[arr[0]]=dis[arr[0]]; for(int i=1;i<pos;i++){ d[arr[i]]=d[arr[i-1]]+dis[arr[i]]; } for(int i=0;i<pos;i++){ ans+=dis[arr[i]]*(d[arr[pos-1]]-d[arr[i]])+dis[arr[i]]; } } } cout<<ans<<endl; return 0; }
G eli和字符串:
VECTOR保存每个字符的位置。然后暴力枚举
#include<bits/stdc++.h> using namespace std; const int INF=1E9+7; vector<int >ve[10000]; int main(){ int n,k; cin>>n>>k; string s; cin>>s; for(int i=0;i<n;i++){ ve[s[i]].push_back(i); } int ans=INF; for(char i='a';i<='z';i++){ int x=ve[i].size(); if(x<k) continue ; for(int j=0;j<=x-k;j++){ ans=min(ans,ve[i][j+k-1]-ve[i][j]+1); } } if(ans==INF) cout<<-1<<endl; else cout<<ans<<endl; return 0; }
nozomi和字符串
二分答案+双指针
check(int x)函数的书写:用双指针,求出长度为x时的0的个数与1的个数,然后向右滑动,同时判断只要0和1的个数有一个小于等于k就满足条件
#include<bits/stdc++.h> using namespace std; int n,k; string s; bool check(int x){ int a0=0,a1=0; int l=0,r=x-1; for(int i=0;i<=x-1;i++){ if(s[i]=='0') a0++; else a1++; } if(a0<=k||a1<=k) return 1; l++,r++; for(;l<=n-x&&r<=n-1;l++,r++){ if(s[l-1]=='0') a0--; else a1--; if(s[r]=='0') a0++; else a1++; if(a0<=k||a1<=k) return 1; } return 0; } int main(){ cin>>n>>k; cin>>s; int left=0; int right=n; int ans=0; check(4); while(left<=right){ int mid=(left+right)/2; if(check(mid)){ left=mid+1; ans=max(ans,mid); } else { right=mid-1; } } cout<<ans<<endl; return 0; }
nico和niconiconi
DP问题
以最后一个字符为标准,判断前面的字符满足那个条件
满足条件a的话,答案为dp[i]=max(dp[i],dp[i-4]+a)
满足条件b的话,答案为dp[i]=max(dp[i],dp[i-6]+a) ,dp[i]=max(dp[i],dp[i-6]+b)
满足条件c的话,答案为dp[i]=max(dp[i],dp[i-10]+c),dp[i]=max(dp[i],dp[i-10]+a+b),dp[i]=max(dp[i],dp[i-10]+a+a)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=3e5+7; char s[N]; ll dp[N]; int main() { ll n,a,b,c; cin>>n>>a>>b>>c; scanf("%s",s+1); for(ll i=1;i<=n;i++){ dp[i]=max(dp[i],dp[i-1]); if(s[i]=='o'&&i>=4){ if(s[i-1]=='c'&&s[i-2]=='i'&&s[i-3]=='n') dp[i]=max(dp[i],dp[i-4]+a); } if(s[i]=='i'&&i>=6){ if(s[i-1]=='n'&&s[i-2]=='o'&&s[i-3]=='c'&&s[i-4]=='i'&&s[i-5]=='n'){ dp[i]=max(dp[i],dp[i-6]+b); dp[i]=max(dp[i],dp[i-6]+a); } } if(s[i]=='i'&&i>=10){ if(s[i-1]=='n'&&s[i-2]=='o'&&s[i-3]=='c'&&s[i-4]=='i'&&s[i-5]=='n'&&s[i-6]=='o'&&s[i-7]=='c'&&s[i-8]=='i'&&s[i-9]=='n'){ dp[i]=max(dp[i],dp[i-10]+c); dp[i]=max(dp[i],dp[i-10]+a+b); dp[i]=max(dp[i],dp[i-10]+a+a); } } } cout<<dp[n]<<endl; return 0; }
J 待补