比賽地址:https://ac.nowcoder.com/acm/contest/3002
比賽來源:2020牛客寒假算法基礎集訓營1
文章目錄
A honoka和格點三角形(思維)
思路:首先是樣例中給出的 6 種三角形,其次還有 4 種三角形如下圖:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int main(){
int n,m; scanf("%d%d",&n,&m);
ll ans;
ans=((1ll*(m-2)*(n-1)*6)%mod+(1ll*(n-2)*(m-1)*6)%mod)%mod;
ans=(ans+((((1ll*(n-2)*(m-1))%mod)*(m-2))%mod)*2)%mod;//非特殊
ans=(ans+((((1ll*(m-2)*(n-1))%mod)*(n-2))%mod)*2)%mod;//非特殊
ans=(ans+((((1ll*(n-1)*(m-2))%mod)*(m-3))%mod)*2)%mod;//非特殊
ans=(ans+((((1ll*(m-1)*(n-2))%mod)*(n-3))%mod)*2)%mod;//非特殊
printf("%lld\n",ans);
return 0;
}
B kotori和bangdream(概率)
思路:簽到題,直接計算即可。
#include<bits/stdc++.h>
using namespace std;
int main(){
double n,x,a,b; scanf("%lf%lf%lf%lf",&n,&x,&a,&b);
double ans=(x*a+(100-x)*b)*n/100;
printf("%.2f\n",ans);
return 0;
}
D hanayo和米飯
直接記錄出現的數字,遍歷查找未出現過得數字。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int a[maxn];
map<int,int>m;
int main(){
int n; scanf("%d",&n);
for(int i=1;i<=n-1;i++){
scanf("%d",&a[i]);
m[a[i]]++;
}
for(int i=1;i<=n;i++){
if(!m[i]){
printf("%d\n",i);
break;
}
}
return 0;
}
E rin和快速迭代(因子個數)
思路:模板題,查找因子並且記錄個數,注意點見代碼。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll solve(ll n){
ll cnt1=0;
while(n!=2){
ll cnt=0; cnt1++;
for(long long i=1;i*i<=n;i++){//sqrt(n)會出錯
if(n%i==0){
if(i*i==n) cnt++;
else cnt+=2;
}
}
n=cnt;
}
return cnt1;
}
int main(){
ll n; scanf("%lld",&n);
ll cnt=solve(n);
printf("%lld\n",cnt);
return 0;
}
F maki和tree(並查集)
思路:滿足題意的情況爲黑點在路徑中間和黑點是端點的情況,我們用並查集可以先預處理出每一個白點連通塊並且記錄每一個連通塊中白點的數量。黑點是端點的情況我們直接加與這個點連接的連通塊的白點的個數,在中間的情況見下圖。
2 和 3 到 1 的路徑,3 到 2 的路徑。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
char str[maxn];
int cnt=0,head[maxn],f[maxn],size[maxn];
struct Edge{
int u,v,next;
}edge[maxn<<1];
void addedge(int u,int v){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
int Find(int v){
if(f[v]==v) return v;
else return f[v]=Find(f[v]);
}
void Merge(int u,int v){
int t1=Find(u),t2=Find(v);
if(t1!=t2){
f[t1]=t2;//t1的父節點爲t2
size[t2]+=size[t1];
}
}
int main(){
int n; scanf("%d",&n);
scanf("%s",str+1);
for(int i=1;i<=n;i++){
size[i]=(str[i]=='W');
f[i]=i; head[i]=-1;
}
for(int i=1;i<=n-1;i++){
int u,v; scanf("%d%d",&u,&v);
addedge(u,v); addedge(v,u);
if(str[u]==str[v]&&str[u]=='W') Merge(u,v);//預處理出所有的白色連通塊
}
//for(int i=1;i<=n;i++) cout<<size[i]<<" "; cout<<endl;
ll sum=0;
for(int i=1;i<=n;i++){
if(str[i]=='B'){
ll cnt1=0;
for(int j=head[i];j!=-1;j=edge[j].next) cnt1+=(ll)size[Find(edge[j].v)];//端點
sum+=cnt1;
for(int j=head[i];j!=-1;j=edge[j].next){//中間
cnt1-=(ll)size[Find(edge[j].v)];
sum+=1ll*cnt1*size[Find(edge[j].v)];
}
}
}
printf("%lld\n",sum);
return 0;
}
G eli和字符串(二分)
思路:直接二分長度,然後判斷此長度下的子字符串中每一個字符出現的次數。如果滿足題意,那麼再找是否有更短的字符串;若不滿足題意,就找更長的字符串。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
char str[maxn];
int cnt[30],n,k;
bool check(int len){
for(int i=0;i<30;i++) cnt[i]=0;
for(int i=0;i<len;i++){
cnt[str[i]-'a']++;
if(cnt[str[i]-'a']==k) return true;
}
for(int i=len;i<n;i++){
cnt[str[i-len]-'a']--; cnt[str[i]-'a']++;
if(cnt[str[i]-'a']==k) return true;
}
return false;
}
int main(){
scanf("%d%d",&n,&k);
scanf("%s",str);
int l=1,r=n,ans=-1;
while(l<=r){
int mid=l+(r-l)/2;
if(check(mid)){
r=mid-1;
ans=mid;
}else l=mid+1;
}
printf("%d\n",ans);
return 0;
}
H nozomi和字符串(二分)
思路:同 G ,二分長度,記錄此長度下,每一個子串 0 1 的個數,如果小的那個小於等於 k,則滿足題意,再找是否存在更長的字符串,否則答案可能更短。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
char str[maxn];
int cnt[2],n,k;
bool check(int len){
cnt[0]=cnt[1]=0;
for(int i=0;i<len;i++) cnt[str[i]-'0']++;
for(int i=0;i<len;i++){
if(min(cnt[0],cnt[1])<=k) return true;
}
for(int i=len;i<n;i++){
cnt[str[i-len]-'0']--; cnt[str[i]-'0']++;
if(min(cnt[0],cnt[1])<=k) return true;
}
return false;
}
int main(){
scanf("%d%d",&n,&k);
scanf("%s",str);
int l=1,r=n,ans=0;
while(l<=r){
int mid=l+(r-l)/2;
if(check(mid)){
l=mid+1;
ans=mid;
}else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
I nico和niconiconi(DP)
思路: 表示截止到當前字符最大的計分分數。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+20;
ll dp[maxn];
string str;
int main(){
int n,a,b,c; cin>>n>>a>>b>>c;
cin>>str;
for(int i=1;i<n;i++){
dp[i]=max(dp[i],dp[i-1]);
if(i>=3&&str.substr(i-3,4)=="nico") dp[i]=max(dp[i],dp[i-3]+(ll)a);
if(i>=5&&str.substr(i-5,6)=="niconi") dp[i]=max(dp[i],dp[i-5]+(ll)b);
if(i>=9&&str.substr(i-9,10)=="niconiconi") dp[i]=max(dp[i],dp[i-9]+(ll)c);
}
printf("%lld\n",dp[n-1]);
return 0;
}