【NOIP2014TG】solution
链接:https://www.luogu.org/problem/lists?name=&orderitem=pid&tag=83|31
D1T1(rps)
题意:给你一个周期,以及胜负关系,求A和B的胜场。
解题思路:暴力抄表,然后暴力计算即可。
#include<cstdio> #include<iostream> using namespace std; int a[201],na,nb,b[201],ansa,ansb,n; int f[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=1; i<na; i++) scanf("%d",&a[i]); cin>>a[0]; for (int i=1; i<nb; i++) scanf("%d",&b[i]); cin>>b[0]; for (int i=1; i<=n; i++){ ansa+=f[a[i%na]][b[i%nb]]; ansb+=f[b[i%nb]][a[i%na]]; } cout<<ansa<<" "<<ansb; }
D1T2(link)
题意:给你棵树,求最大联合权值与联合权值和,(联合权值:距离为2的2个点的点权之积)
解题思路:枚举所有中间点,暴力算出所有的与其相连的点权之和与其点权平方和,用数学公式求出乘积和,最大的较好做,不多解释。
#include <stdio.h> #define MN 200005 #define mod 10007 #define ll long long #define v edge[j].to #define max(a,b) ((a)>(b)?(a):(b)) int w[MN],head[MN],n,maxx,sum,cnt; struct zxy{ int to,nxt; }edge[MN<<1]; inline int in(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar(); while(ch>='0'&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f; } inline void ins(int x,int y){edge[++cnt].to=y,edge[cnt].nxt=head[x],head[x]=cnt;} void init(){ n=in(); for (int i=1; i<n; ++i){ register int x=in(),y=in(); ins(x,y);ins(y,x); } for (register int i=1; i<=n; ++i) w[i]=in(); } void solve(){ for (register int i=1; i<=n; ++i){ register ll tmp=0,tmpp=0;register int ma1=0,ma2=0; for (register int j=head[i]; j; j=edge[j].nxt){ tmp+=w[v],tmpp+=w[v]*w[v],tmp%=mod,tmpp%=mod; if (w[v]>ma1) ma2=ma1,ma1=w[v]; else ma2=max(ma2,w[v]); } maxx=max(maxx,ma1*ma2),sum+=tmp*tmp-tmpp;sum%=mod; } printf("%d %d\n",maxx,sum); } int main(){init();solve();}
D1T3(bird)
题意:看题目吧= =就是flappy birds啊
解题思路:每次点击看成一个费用为1,体积为X[i]的物品,反之则。。。。然后按题意跑一遍求最小费用的背包,注意对高度>m的特殊处理与管道的判断。
#include <stdio.h> #include <string.h> #define MN 10005 #define MM 1005 #define inf 0x3f3f3f3f #define min(a,b) ((a)<(b)?(a):(b)) int n,m,k,up[MN],down[MN],dp[2][MM],bot[MN],top[MN],ansn,ans; inline int in(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } void init(){ n=in(),top[n]=m=in(),k=in(); for (int i=0; i<n; ++i) top[i]=m,up[i]=in(),down[i]=in(); for (register int i=1,s; i<=k; ++i) bot[s=in()]=in()+1,top[s]=in()-1; } void solve(){ for (register int i=1; i<=n; ++i){ memset(dp[i&1],0x3f,sizeof(dp[i&1])); register int minn=inf; for (register int j=up[i-1]+1; j<m; ++j) dp[i&1][j]=min(dp[i&1][j-up[i-1]]+1,min(dp[(i&1)^1][j-up[i-1]]+1,dp[i&1][j])); for (register int j=m-up[i-1]; j<=m; ++j) dp[i&1][m]=min(dp[i&1][j]+1,min(dp[i&1][m],dp[(i&1)^1][j]+1)); for (register int j=down[i-1]+1; j<=m; ++j) dp[i&1][j-down[i-1]]=min(dp[(i&1)^1][j],dp[i&1][j-down[i-1]]); for (register int j=0; j<bot[i]; ++j) dp[i&1][j]=inf; for (register int j=top[i]+1; j<=m; ++j) dp[i&1][j]=inf; for (register int j=bot[i]; j<=top[i]; ++j) minn=min(minn,dp[i&1][j]); if (minn==inf){ puts("0"); printf("%d",ansn); return; } if ((top[i]^m)&&(bot[i])) ++ansn; }ans=inf; for (register int j=1; j<=m; ++j) ans=min(ans,dp[n&1][j]); printf("1\n%d",ans); } int main(){init();solve();}
D2T1(wireless)
我写了傻逼做法,反正这题就是傻逼模拟。
#include<stdio.h> #define MN 130 #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) int f[MN][MN],n,d,ans[MN][MN],ma,summ; inline int in(){ int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } int main(){ d=in();n=in(); for (int i=1; i<=n; ++i){ int x=in(),y=in(),l=in(); f[x][y]=l; } for (register int i=0; i<129; ++i) for (register int j=0; j<129; ++j){ for (register int a=max(0,i-d); a<=min(128,i+d); ++a) for (register int b=max(0,j-d); b<=min(128,j+d); ++b) ans[i][j]+=f[a][b]; ma=max(ans[i][j],ma); } for (register int i=0; i<129; ++i) for (register int j=0; j<129; ++j) if (ma==ans[i][j]) summ++; printf("%d %d",summ,ma); }
D2T2(road)
题意:看题目吧= =。
解题思路:首先建反边然后从终点bfs一遍,计算一下入度,然后判断一下是否可行,再正向bfs一遍即可。
#include <stdio.h> #include <string.h> #define MN 10005 #define ME 200005 int head[MN],dis[MN],n,e,fb[MN],cnt,s,t,que[MN],du[MN],cntt[MN]; bool vis[MN]; struct zxy{ int to,nxt; }edge[ME<<1]; inline void ins(int x,int y,int *h){edge[++cnt].to=y,edge[cnt].nxt=h[x],h[x]=cnt;} inline int in(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x; } inline void bfs(int s,int *hd){ int h=0,t=1;que[1]=s; memset(dis,127/3,sizeof(dis)); dis[s]=0;vis[s]=1; while(h<t){ for (register int i=hd[que[++h]]; i; i=edge[i].nxt){ register int v=edge[i].to;++cntt[v]; if (!vis[edge[i].to]){ dis[v]=dis[que[h]]+1;vis[v]=1;que[++t]=v; } } } } void init(){ n=in(),e=in(); for (register int i=1; i<=e; ++i){ register int x=in(),y=in();++du[x]; ins(x,y,head);ins(y,x,fb); } s=in(),t=in(); } void solve(){ bfs(t,fb);for (register int i=1; i<=n; ++i) vis[i]=du[i]!=cntt[i]; bfs(s,head);if (!vis[t]){puts("-1");return;} printf("%d",dis[t]); } int main(){init();solve();return 0;}
D2T3(equation)
题意:看题目
解题思路:大丧题,欺负我数学不好。我们考虑选取mo数,然后优化掉高精度操作,然后注意一下多个mo防止出现恰好为mo数倍数的解,多用几个10000左右的质数应该就比较稳了。
#include <stdio.h> #define MN 105 #define MM 1000005 #define ML 10005 const int mod[5]={10007,10009,10037,10039,10061}; int a[5][MN],ans[MM],ansn,n,b[5][13005],m;char ch[ML]; inline void check(int x){ for (register int i=0; i<5; ++i) for (register int j=n; j>=0; --j) b[i][x%mod[i]]=(b[i][x%mod[i]]*(x%mod[i])+a[i][j])%mod[i]; } inline bool judge(int x){ for (register int i=0; i<5; ++i) if (b[i][x%mod[i]]) return 0; return 1; } void init(){ scanf("%d%d",&n,&m);for (int i=0; i<=n; ++i){ scanf("%s",ch);for (register int j=0; ch[j]; ++j) if (ch[j]>='0'&&ch[j]<='9') for (register int k=0; k<5; ++k) a[k][i]=(a[k][i]*10+ch[j]-'0')%mod[k]; if (ch[0]=='-') for (register int k=0; k<5; ++k) a[k][i]*=-1; } } void solve(){ for (register int i=0; i<10061; ++i) check(i); for (register int i=1; i<=m; ++i) if (judge(i)) ans[++ansn]=i; printf("%d\n",ansn); for (register int i=1; i<=ansn; ++i) printf("%d\n",ans[i]); } int main(){init();solve();}