NOIP2017赛前模拟10月30日总结

题目1:

  n个人参赛(n<=100000),每个人有一个权值··已知两个人权值绝对值之差小于等于K时,两个人都有可能赢,若大于则权值大的人赢···比赛为淘汰制,进行n-1轮·问最后可能赢的人有多少个?

    考点:简单分析

  直接将权值排序,从大到小扫一遍直到num[i+1]-num[i]>k停止··此时答案等于n-i

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5;
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<'0'||c>'9';c=getchar());
  for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0';
  return f;
}
int n,k,T,num[N];
int main()
{
  T=R();
  while(T--)
  {
    n=R(),k=R();
    for(int i=1;i<=n;i++)  num[i]=R();
    sort(num+1,num+n+1);
    int ans=1;
    for(int i=n-1;i>=1;i--)
    {
      if(num[i+1]-num[i]<=k)  ans++;
      else break;
    }
    cout<<ans<<"\n";
  }
  return 0;
}

 

题目2:

  有n个数从左到右排列··豆豆和豆沙从左到右交替取,豆豆第一次可以取1个或2个数,之后若前一个人拿了K个数··则后面的人只能拿K或K+1个数··n<=20000,若每次两人拿的时候都采用最优策略,那么豆豆会比豆沙多拿总和多大的数?

  考点:dp

  和第一次NOIP总结中的T2很像··我们用f[i][j]表示先手从i开始拿j个之后能最多比后手多拿多大,得出转移方程:

   f[i][j]=sum[i+j-1]-sum[i-1]-max(f[i+j][j],f[i+j][j+1]);

   sum为数的前缀和,最后比较f[1][1]和f[1][2]即可,由于j每次枚举最大不会超过根号n,复杂度为n^3/2; 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e4+5;
int T,n,f[N][205],num[N],sum[N];
inline int R(){
    char c;int f=0,i=1;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')  i=-1,c=getchar();
    for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0';
    return f*i;
}
int main()
{
    T=R();  
    while(T--){
        memset(sum,0,sizeof(sum));memset(f,0,sizeof(f));
        n=R();
        for(int i=1;i<=n;i++)    sum[i]=num[i]=R(),sum[i]+=sum[i-1];
        for(int i=n;i>=1;i--)
            for(int j=1;i+j-1<=n&&j<=200&&j<=i+1;j++)
                f[i][j]=sum[i+j-1]-sum[i-1]-max(f[i+j][j],f[i+j][j+1]);
        cout<<max(f[1][2],f[1][1])<<endl;
    }
    return 0;
}

 

题目3:

  给定一个无向图,问图中共边三元环有多少对,点数n<=100000,m<=200000;

  考点:图论

  很妙的一道题···我们枚举每一个点u··然后找到与该点相连且度数比该点小的点v··然后找既与v相连由于u相连的点的数量计算对答案贡献即可··复杂度为m^3/2次方

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int M=2e5+5;
const int N=1e5+5;
vector<int>ed[N];
inline int R(){
    char c;int f=0;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(;c<='9'&&c>='0';c=getchar())    f=(f<<3)+(f<<1)+c-'0';    
    return f;
}
int T,n,m,du[N],tag[N],tim;
long long ans=0;
inline void pre(){
    for(int i=1;i<=n;i++)    ed[i].clear();
    memset(du,0,sizeof(du));tim=0;ans=0;
    memset(tag,0,sizeof(tag));
}
inline void getans(){
    for(int i=1;i<=n;i++){
        tim++;
        for(int j=0;j<ed[i].size();j++)  
        {
            int v=ed[i][j];tag[v]=tim;
        }
        for(int j=0;j<ed[i].size();j++){
            int v=ed[i][j];
            if(du[v]<du[i]||(du[v]==du[i]&&v<i)){
                int cnt=0;
                for(int k=0;k<ed[v].size();k++)        if(tag[ed[v][k]]==tim)    cnt++;
                ans+=(long long)cnt*(cnt-1)/2;
            }
        }
    }
}
int main()
{
    T=R();
    while(T--){
        n=R(),m=R();pre();int a,b;
        for(int i=1;i<=m;i++)    a=R(),b=R(),du[a]++,du[b]++,ed[a].push_back(b),ed[b].push_back(a);    
        getans();cout<<ans<<endl;
    }
    
}

 

       

转载于:https://www.cnblogs.com/AseanA/p/7755752.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值