【noip2014】day1
T1
[模拟]
找循环节直接模拟即可。
【code】
#include<bits/stdc++.h> using namespace std; #define ll long long #define File "rps" inline void file(){ freopen(File".in","r",stdin); freopen(File".out","w",stdout); } inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();} return x*f; } const int MAXN = 200 + 10; int n, na, nb, a[MAXN], b[MAXN], cnta, cntb; int vs[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(){ file(); n = read(),na = read(),nb = read(); for(int i = 0;i < na; ++i) a[i] = read(); for(int i = 0;i < nb; ++i) b[i] = read(); for(int i = 0; i < n; i++){ cnta += vs[a[i % na]][b[i % nb]]; //周期循环 cntb += vs[b[i % nb]][a[i % na]]; } printf("%d %d\n",cnta,cntb); return 0; }
T2
[搜索?]
题意实际上就是要找到(a,b,c)满足a对b连边,b对c连边,求出树上所有这样的三元组的组数的联合权值,以及最大的联合权值。
我们只需枚举中间点是哪一个。
然后遍历它的所有出边,统计答案即可。
还要记得开longlong
求和可能会炸int
【code】
#include<bits/stdc++.h> using namespace std; #define ll long long #define File "link" inline void file(){ freopen(File".in","r",stdin); freopen(File".out","w",stdout); } inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();} return x*f; } const int mxn = 2e5 + 10; const int mod = 10007; int n; int w[mxn]; struct edge{ int nxt,y; }e[mxn<<1]; int to[mxn],len; inline void add(int xx,int yy){ e[++len].nxt = to[xx]; to[xx] = len; e[len].y = yy; } int main(){ file(); n = read(); for(int i = 1;i < n; ++i){ int x = read(),y = read(); add(x,y),add(y,x); } for(int i = 1;i <= n; ++i) w[i] = read(); ll mx1(0),s1(0); ll mx2(0),s2(0); for(int x = 1;x <= n; ++x){ s2 = mx2 = 0; for(int i = to[x]; i;i = e[i].nxt){ int y = e[i].y; s1 = (s1 + 1ll*s2*w[y]) % mod; mx1 = max(mx1,1ll*mx2*w[y]); s2 = (s2 + (ll)w[y]) % mod; mx2 = max(mx2,(ll)w[y]); } } printf("%lld %lld\n",mx1,s1*2%mod); return 0; } /* 5 1 2 2 3 3 4 4 5 1 5 2 3 10 */
T3
[dp]
本题主要考虑的是如何满足水管在的情况。
F[i][j]表示横坐标为i,竖直距离为j的最少点击次数。
F[i][j] = min(f[i-1][j-x[i]],f[i][j-x[i]])+1;
F[i][j] = min(f[i][j],f[i-1][j+y[i]]);
如何保证不超过上下边界通过水管?
Dp值更新完之后,在边界以外的dp值赋为正无穷就好了。
由于能够转移而来的初值有限。所以f[0][i] = 0外其余均为正无穷。
【code】
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf f[0][0] #define File "bird" inline void file(){ freopen(File".in","r",stdin); freopen(File".out","w",stdout); } inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();} return x*f; } const int mxn = 1e4 + 5; const int mxm = 2e3 + 5; int n,m,k; int x[mxn],y[mxn]; bool v[mxn]; int l[mxn],h[mxn]; //每个位置可以飞到的上下界。 int f[mxn][mxm]; //横坐标为i高度为j的最少点击次数。 inline int min_(int x,int y){ return x > y ? y : x; } int main(){ file(); n = read(),m = read(),k = read(); for(int i = 1;i <= n; ++i) x[i] = read(),y[i] = read(),l[i] = 1,h[i] = m; memset(v,0,sizeof v); for(int i = 1;i <= k; ++i){ int p = read(),a = read(),b = read(); l[p] = a+1, h[p] = b-1; v[p] = 1; } memset(f,0x3f,sizeof f); for(int i = 1;i <= m; ++i) f[0][i] = 0; //初值 for(int i = 1;i <= n; ++i){ for(int j = x[i]+1;j <= x[i]+m; ++j) f[i][j] = min_(f[i-1][j-x[i]],f[i][j-x[i]])+1; for(int j = m+1;j <= x[i]+m; ++j) f[i][m] = min_(f[i][m],f[i][j]); for(int j = 1;j <= m-y[i]; ++j) f[i][j] = min_(f[i][j],f[i-1][j+y[i]]); for(int j = 1;j < l[i]; ++j) f[i][j] = inf; for(int j = h[i]+1;j <= m; ++j) f[i][j] = inf; } int ans = inf; for(int i = 1;i <= m; ++i) ans = min_(ans,f[n][i]); if(ans < inf){ puts("1"); printf("%d\n",ans); return 0; } puts("0"); bool f_ = 1; int i,j; for(i = n;i >= 1; --i){ for(j = 1;j <= m; ++j){ if(f[i][j] < inf) { break; } } if(j <= m) break; } ans = 0; for(int j = 1;j <= i; ++j) if(v[j]) ans++; printf("%d\n",ans); return 0; } /* 10 10 4 1 2 3 1 2 2 1 8 1 8 3 2 2 1 2 1 2 2 1 2 1 0 2 6 7 9 9 1 4 3 8 10 */
G102的孤儿们都要好好的啊。