1. 程式人生 > >暑假最後一測

暑假最後一測

分享 close img 顏色 進入 opened cst 四種 ons

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

題解:

第一題:裸的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\n", t); else puts("ZenMeZheMeDuo"); } }
View Code

第二題:原題,考慮邊的貢獻,註意背包順序,有搞了好久;

技術分享圖片
#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("\n%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\n", dp[1][m]);
}
View Code

第三題: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\n",(f)?(ans>>1):ans);
    return 0;
}
View Code

開學了……O__O"…

暑假最後一測