暑假最后一测
Posted edsheeran
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了暑假最后一测相关的知识,希望对你有一定的参考价值。
题解:
第一题:裸的exgcd,注意有很多特判;
#include<bits/stdc++.h> using namespace std; #define ll long long const ll P = 65535; ll exgcd(ll a, ll b, ll &x, ll &y){ if(!b){ x = 1; y = 0; return a; } ll x0, y0; ll d = exgcd(b, a%b, x0, y0); x = y0; y = x0 - (a/b) * y0; return d; } int main(){ // freopen("fuction.in","r",stdin); // freopen("fuction.out","w",stdout); int T; scanf("%d", &T); while(T--){ ll a, b, c; scanf("%I64d%I64d%I64d", &a, &b, &c); if((!a && !b && c)){puts("0");continue;} if((!a && !b && !c)){puts("ZenMeZheMeDuo");continue;} if(!a || !b){ if((!a && c * b > 0 && c%b == 0) || (!b && a * c > 0 && c%a == 0))puts("ZenMeZheMeDuo"); else puts("0"); continue; } ll x, y; ll d = exgcd(a, b, x, y); if(c % d){puts("0");continue;} x *= c/d; y *= c/d; if((a > 0 && b < 0) || (a < 0 && b > 0)){puts("ZenMeZheMeDuo");continue;} ll deltax = b/d, deltay = a/d; deltax = abs(deltax), deltay = abs(deltay); ll x1 = (x % deltax + deltax) % deltax; if(!x1) x1 += deltax; ll y2 = (c - x1 * a) / b; ll yy1 = (y % deltay + deltay) % deltay; if(!yy1) yy1 += deltay; ll x2 = (c - yy1 * b) / a; if(y2 <= 0 || x2 <= 0){puts("0");continue;} ll t = (x2 - x1) / deltax + 1; if(t <= P)printf("%I64d ", t); else puts("ZenMeZheMeDuo"); } }
第二题:原题,考虑边的贡献,注意背包顺序,有搞了好久;
#include<bits/stdc++.h> using namespace std; #define ll long long const int M = 2005; const ll inf = -1e8; int h[M], siz[M], tot; ll dp[M][M]; int n, m; struct edge{int v, nxt, w;}G[M << 2]; void add(int u, int v, int w){ G[++tot].v = v; G[tot].w = w; G[tot].nxt = h[u]; h[u] = tot; } void dfs(int u, int f){ dp[u][0] = dp[u][1] = 0; siz[u] = 1; int child = 0; for(int i = h[u]; i; i = G[i].nxt){ int v = G[i].v; if(v == f)continue; dfs(v, u); child++; siz[u] += siz[v]; for(int k = min(siz[u], m); k >= 0; k--) for(int kk = 0; kk <= min(siz[v], k); kk++){ if(dp[u][k - kk] > inf){ ll val = 1LL*(1LL* kk * (m - kk) + 1LL * (siz[v] - kk) * (n - siz[v] - m + kk) ) * G[i].w; dp[u][k] = max(dp[u][k], dp[u][k - kk] + dp[v][kk] + val); } } } // printf(" %d ",u); // for(int i = 0; i <= m; i++)printf(" %I64d", dp[u][i]); } int main(){ freopen("coloration.in","r",stdin); freopen("coloration.out","w",stdout); scanf("%d%d", &n, &m); memset(dp, 0x8f, sizeof(dp)); int u, v, w; for(int i = 1; i < n; i++){ scanf("%d%d%d", &u, &v, &w); add(u, v, w); add(v, u, w); } dfs(1, 0); printf("%I64d ", dp[1][m]); }
第三题:70的模拟分,我一分都没拿到,我一直在边上弄,其实应该在格点上做,就没有这么多边缘问题了;
100分:
光线只有遇上边界或堵塞的格子才会改变方向,所以改变方向的位置是有限的,光线的方向又最多只有四种,所以光线在循环之前改变方向的次数是O(n+m+k)级别的。我们可以模拟光线的移动。已知光线位置和光线的方向,使用二分的方法可以在O(log k)的时间复杂度内求出即将改变方向的位置和改变后的方向。
我们对网格进行染色,有邻边的格子颜色不同,形成一个二分图。根据题目中光线反射的方式,可以发现,每当光线沿西北、东南方向前进时,只会经过一种颜色的网格,每当光线沿东北、西南方向前进时,只会经过另一种颜色的网格。所以光线在某一个格子中心时,要么只会是西北、东南方向之一,要么只会是东北、西南方向之一,就不会出现交叉的情况;
这样,如果一次循环内一个格子被重复经过,只有可能是光线以相反的两个方向进入,并且一次循环内一个格子最多被经过两次。一个格子被经过两次,所有被光线经过的格子都会被经过两次。易知,如果光线在前进过程中出现过如下两种反射,所有格子就会被经过两次。只需在模拟的过程中记录是否出现过这两种情况即可。
对于二分,由于对角线颜色一样,我们可以对对角线开vector存障碍,对角线x+y或y-x是不变的,可以作为编号;
以下是std,写的很难看
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; const int N=100005; int n,m,k,dx,dy,x,y; long long ans; bool f; char ch[10]; struct qwe { int x,y; qwe(int X=0,int Y=0) { x=X,y=Y; } bool operator < (const qwe &b) const { return x<b.x||(x==b.x&&y<b.y); } }; vector<qwe>a[2]; int read() { int r=0,f=1; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r*f; } void add(int x,int y) { a[0].push_back(qwe(x-y,x)); a[1].push_back(qwe(x+y,x)); } void wk() { int fl=(dx!=dy); qwe p=fl?qwe(x+y,x):qwe(x-y,x); vector<qwe>::iterator it=upper_bound(a[fl].begin(),a[fl].end(),p); for(;it->x!=p.x;it--); if(dx<0) for(;it->y>=x;it--); ans+=abs(x-it->y)-1; x=it->y,y=fl?it->x-x:x-it->x; bool u=binary_search(a[0].begin(),a[0].end(),qwe(x-y-dx,x-dx)),v=binary_search(a[0].begin(),a[0].end(),qwe(x-y+dy,x)); if(u==v) f=1,dx*=-1,dy*=-1; else if(u) x-=dx,dy*=-1; else if(v) y-=dy,dx*=-1; } int main() { freopen("ray.in","r",stdin); freopen("ray.out","w",stdout); n=read(),m=read(),k=read(); for(int i=1;i<=m;i++) add(0,i),add(n+1,i); for(int i=0;i<=n+1;i++) add(i,0),add(i,m+1); for(int i=1;i<=k;i++) { int x=read(),y=read(); add(x,y); } x=read(),y=read(); scanf("%s",ch); dx=(ch[0]==‘N‘)?-1:1,dy=(ch[1]==‘W‘)?-1:1; sort(a[0].begin(),a[0].end()); sort(a[1].begin(),a[1].end()); wk(); int sx=x,sy=y,sdx=dx,sdy=dy; ans=0; do wk(); while(!(x==sx&&y==sy&&dx==sdx&&dy==sdy)); printf("%I64d ",(f)?(ans>>1):ans); return 0; }
开学了……O__O"…
以上是关于暑假最后一测的主要内容,如果未能解决你的问题,请参考以下文章