NOIP 2014

生活大爆炸版石头剪刀布

题目
模拟。

#include <bits/stdc++.h>
using namespace std;
int n,na,nb,a[2001],b[2001],ans1,ans2;
int score[5][5]={{0,0,1,1,0},{1,0,0,1,0},{0,1,0,0,1},{0,0,1,0,1},{1,1,0,0,0}};
int main()
{
    cin >>n>>na>>nb;
    for(int i=0;i<na;i++) cin>>a[i];
    for(int i=0;i<nb;i++) cin>>b[i];
    for(int i=0;i<n;i++)
    {
        ans1+=score[a[i%na]][b[i%nb]]; 
        ans2+=score[b[i%nb]][a[i%na]];
    }
    cout<<ans1<<" "<<ans2<< endl;
    return 0;
}

联合权值

题目
对于一个点,我们把它的出点放到一个vector里面,任选两个点就是距离为\(2\)的点对。
把每个点的出点vector遍历一遍,记录一下前缀和和前缀最大值就行了。

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
const int N=200007,P=10007;
int max(int a,int b){return a>b? a:b;}
int inc(int a,int b){return a+=b,a>=P? a-P:a;}
int mul(int a,int b){return a*b%P;}
int n,w[N],mx,sum;vector<int>E[N],vec;
void cal(int u)
{
    if(E[u].size()==1) return;
    vec.clear();
    for(int v:E[u]) vec.pb(w[v]);
    sort(vec.begin(),vec.end());
    int s=0,t=0;
    for(int x:vec) sum=inc(sum,mul(x%P,s)),mx=max(mx,x*t),s=inc(x,s),t=max(t,x);
}
int main()
{
    n=read();
    for(int i=1,u,v;i<n;++i) u=read(),v=read(),E[u].pb(v),E[v].pb(u);
    for(int i=1;i<=n;++i) w[i]=read();
    for(int i=1;i<=n;++i) cal(i);
    printf("%d %d",mx,inc(sum,sum));
}

飞扬的小鸟

题目
\(f_{i,j}\)表示坐标为\((x,y)\)的最小点屏幕次数。
首先有\(f_{i,j}=f_{i-1,j+y_i}\)
然后还有\(f_{i,j}=\max\limits_{k\in[1,\lfloor\frac j{x_i}\rfloor]}(f_{i-1,j-k*x_i}+k)\)
然后我们发现后面这个可以变成\(f_{i,j}=\max(f_{i-1,j-x_i},f_{i,j-x_i})+1\)
然后就可以直接dp了。

#include<bits/stdc++.h>
using namespace std;
int read(){int x;scanf("%d",&x);return x;}
int min(int a,int b){return a<b? a:b;}
int max(int a,int b){return a>b? a:b;}
const int N=10007,M=1007,inf=0x3f3f3f3f;
int f[N][M<<1],x[N],y[N],l[N],h[N],vis[N];
int main()
{
    int n=read(),m=read(),k=read(),ans=inf;memset(f,0x3f,sizeof f);
    for(int i=1;i<=n;++i) x[i]=read(),y[i]=read(),h[i]=m;
    for(int i=1,p;i<=k;++i) vis[p=read()]=1,l[p]=read()+1,h[p]=read()-1;
    for(int i=1;i<=m;++i) f[0][i]=0;
    for(int i=1,j;i<=n;++i)
    {
    for(j=x[i]+1;j<=m+x[i];++j) f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1);
        for(j=m+1;j<=m+x[i];++j) f[i][m]=min(f[i][m],f[i][j]);
        for(j=1;j<=m-y[i];++j) f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
    for(j=1;j<l[i];++j) f[i][j]=inf;
    for(j=h[i]+1;j<=m;++j) f[i][j]=inf;
    }
    for(int i=1;i<=m;++i) ans=min(ans,f[n][i]);
    if(ans<inf) return !printf("1\n%d",ans);
    int i,j;
    for(i=n;i;--i)
    {
    for(j=1;j<=m;++j){if(f[i][j]<inf)break;}
    if(j<=m)break;
    }
    ans=0;
    for(j=1;j<=i;++j) if(vis[j]) ++ans;
    printf("0\n%d",ans);
}

无线网络发射器选址

题目
枚举+模拟。

#include<iostream>
using namespace std;
int x,y,d,n,maxm,num,sum=1,cross[170][170];
int main()
{
    cin>>d>>n;
    for(int i=1;i<=n;i++) cin>>x>>y>>cross[x+20][y+20];
    for(int i=20;i<=148;i++)
        for(int j=20;j<=148;j++)
        {
            for(int m=i-d;m<=i+d;m++) for(int k=j-d;k<=j+d;k++) num+=cross[m][k];
            if(maxm==num) sum++; else if(maxm<num) sum=1;
            maxm=max(maxm,num),num=0;
        }
    cout<<sum<<" "<<maxm;
}

寻找道路

题目
先建反图找出所有能够到达终点的点。
然后找出所有符合要求的点。
再跑01最短路。

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}
using namespace IO;
const int N=10001,M=200007;
struct edge{int u,v;}e[M];
vector<int>E[N];int n,m,s,t,vis[N],f[N],dis[N];queue<int>q;
void dfs(int u){vis[u]=1;for(int v:E[u])if(!vis[v])dfs(v);}
int check(int u){for(int v:E[u])if(!vis[v])return 0;return 1;}
int main()
{
    n=read(),m=read();
    for(int i=1,u,v;i<=m;++i) u=read(),v=read(),E[v].pb(u),e[i]={u,v};
    s=read(),t=read(),dfs(t);
    for(int i=1;i<=n;++i) E[i].clear();
    for(int i=1;i<=m;++i) E[e[i].u].pb(e[i].v);
    for(int i=1;i<=n;++i) if(check(i)) f[i]=1;
    if(f[s]) q.push(s);
    for(int u;!q.empty();)
    {
    u=q.front(),q.pop();
    for(int v:E[u]) if(f[v]&&!dis[v]&&v^s) dis[v]=dis[u]+1,q.push(v);
    }
    printf("%d",dis[t]? dis[t]:-1);
}

解方程

题目
枚举,大暴力。
注意一下高精度复杂度过高,可以采用哈希来做。

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=101,P=998244353;
int inc(int a,int b){return a+=b,a>=P? a-P:a;}
int mul(int a,int b){return 1ll*a*b%P;}
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT ;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0,f=0,c=Get();while(!isdigit(c)&&c^'-')c=Get();if(c=='-')f=1,c=Get();while(isdigit(c))x=inc(mul(x,10),c-48),c=Get();return f? inc(-x,P):x;}
}
using namespace IO;
int n,m,a[N];vector<int>ans;
int check(int x)
{
    int ans=0,d=1;
    for(int i=0;i<=n;++i) ans=inc(ans,mul(a[i],d)),d=mul(x,d);
    return !ans;
}
int main()
{
    n=read(),m=read();
    for(int i=0;i<=n;++i) a[i]=read();
    for(int i=1;i<=m;++i) if(check(i)) ans.pb(i);
    printf("%d\n",ans.size());
    for(int x:ans) printf("%d\n",x);
}

猜你喜欢

转载自www.cnblogs.com/cjoierShiina-Mashiro/p/11867681.html