2016 湘潭邀请赛 9/10

这场就没有那么难受了。。。。

A

看了看标算,标算是直接把n mod 2016,我不知道为什么。。。。。
不过直接map循环节也随便搞了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <map>
#include <utility>
#include <string>

using namespace std;

struct matrix {
	int a[2][2];

	void in() {
		cin >> a[0][0];
		cin >> a[0][1];
		cin >> a[1][0];
		cin >> a[1][1];
	}

	void out() const {
		cout << a[0][0] << ' ' << a[0][1] << '\n';
		cout << a[1][0] << ' ' << a[1][1] << '\n';
	}

	matrix operator * (matrix const& oth) const {
		matrix ret;
		for (int i = 0; i < 2; ++i)
			for (int j = 0; j < 2; ++j) {
				ret.a[i][j] = 0;
				for (int k = 0; k < 2; ++k) {
					ret.a[i][j] += a[i][k] * oth.a[k][j];
					ret.a[i][j] %=  7;
				}
			}
		return ret;
	}

	bool operator < (matrix const& oth) const {
		for (int i = 0; i < 2; ++i)
			for (int j = 0; j < 2; ++j)
				if (a[i][j] != oth.a[i][j])
					return a[i][j] < oth.a[i][j];
		return 0;
	}
};

matrix const I = {
	1, 0,
	0, 1
};

int main() {
	map<matrix, int> mp;
	ios::sync_with_stdio(0);
	string s;
	while (cin >> s) {
		mp.clear();
		matrix A;
		A.in();
		mp[I] = 0;
		auto Mul = A;
		int len = 1;
		for (; mp.count(Mul) == 0; Mul = A * Mul, ++len) 
			mp[Mul] = len;
		int beg = mp[Mul];
		// cout << "BEG : " << beg << ' ' << len << '\n';
		int n = 0;
		for (auto c : s) {
			n = n * 10 + c - '0';
			n %= len;
		}
		n = ((n - beg) % len + len) % len;
		for (auto const& mat : mp) 
			if (mat.second == n) {
				mat.first.out();
				break;
			}
	}
}

B

考虑安排一个顺序,也就是把所有的球排成一排,然后依次选第一个,第二个这样。
那么如果是红拿完了,对应的情况应该是,最后一个球为黄/绿,然后去掉那种颜色的球,剩下的球对应的序列的末尾应该是另一种颜色。
然后用这样的思想算一算就行。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
 
using namespace std;
 
using ll = long long;
 
ll gcd_(ll a, ll b) {
    if (b == 0)
        return a;
    return gcd_(b, a % b);
}
 
struct frac {
    ll fz, fm;
 
    frac() {}
 
    frac(ll a, ll b) {
        ll gcd = gcd_(a, b);
        fz = a / gcd;
        fm = b / gcd;
    }
 
    frac operator + (frac const& oth) const {
        auto ret = frac(oth.fz * fm + fz * oth.fm, fm * oth.fm);
        return ret;
    }
};
 
void solve(ll fz, ll c1, ll c2, ll c3) {
    auto t1 = frac(fz, c1 * c2);
    auto t2 = frac(fz, c1 * c3);
    auto t = t1 + t2;
    cout << t.fz << '/' << t.fm;
}
 
int main() {
    ios::sync_with_stdio(0);
    int a, b, c;
    while (cin >> a >> b >> c) {
        solve(b * c, a + b + c, a + c, a + b);
        cout << ' ';
        solve(a * c, a + b + c, b + c, a + b);
        cout << ' ';
        solve(b * a, a + b + c, b + c, a + c);
        cout << '\n';
    }
}

C

看下数据范围即可获得真相。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
 
using namespace std;
 
int main() {
    static int a[100005];
    int const INF = 1e5;
    ios::sync_with_stdio(0);
    int n, m;
    while (cin >> n >> m) {
        fill(a + 1, a + n + 1, INF);
        for (int i = 1; i <= m; ++i) {
            int x, y, z;
            cin >> x >> y >> z;
            if (x + 1 == y)
                a[x] = min(a[x], z);
        }
        int ans = 0;
        for (int i = 1; i < n; ++i)
            if (a[i] == INF) {
                ans = -1;
                break;
            } else
                ans += a[i];
        cout << ans << '\n';
    }
}

D

来自新队友的carry现场,不过虽然也不太难x
考虑mod 3之后的,那么肯定是每一次增加打2操作,都应该是把最大的mod 3后最大的那个替换掉。
当然这是他WA了几发后我过去帮忙的时候想到的。
他的话。。。当然是对于余数2,1,0分类啦

#include <bits/stdc++.h>
using namespace std;
const int maxn=200005,K=1000000007;
int n,m,can,ans,res,A,B,Ahead,Bhead,a[maxn],b[maxn];
bool boo;
bool cmp(int A,int B) { return A>B; }
int main()
{
    while (scanf("%d%d",&n,&m)>0)
    {
        can=0;
        ans=0;
        res=0;
        A=0;
        B=0;
        Ahead=1;
        Bhead=1;
        boo=false;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        for (int i=1,x;i<=n;i++)
        {
            scanf("%d",&x);
            if (x==1) can++,a[++A]=x; else
            if (x%3==2) can++,a[++A]=x; else
            if (x%3==1) can+=2,a[++A]=x; else b[++B]=x;
            res+=(x+2)/3;
        }
        ans=res;
        for (int i=1;i<=m;i++)
        {
            if (!res) break;
            if (can)
            {
                can--;
                res--;
                a[Ahead]-=2;
                if (a[Ahead]>0 && !(a[Ahead]%3)) b[++B]=a[Ahead++];
                if (a[Ahead]<=0) Ahead++;
            } else
            {
                if (!boo) boo=true,sort(b+1,b+1+B,cmp);
                if (b[Bhead]>3) can+=2,b[Bhead]-=6; else
                can++,b[Bhead]=0;
                if (!b[Bhead]) Bhead++; else
                if (b[Bhead]==3) b[++B]=3,Bhead++;
            }
            ans=(ans+res)%K;
        }
        printf("%d\n",ans);
    }
    return 0;
}

E

显然就是前缀和一下,然后枚举位置分类大讨论,每个位置贡献多少答案这样。。。
但是都不敢写。
这时候就要小洛洛神仙下凡啦!

#include <cstdio>
#include <cstring>
#include <utility>
#include <cstdlib>
#include <algorithm>
#include <cstdint>
#include <vector>
#include <iostream>
#include <array>
 
struct P {
    int x, y;
};
 
using i64 = int64_t;
 
const int Maxx = 1005;
using Mat = std::array<std::array<i64, Maxx * 2>, Maxx>;
using Mat2 = std::array<std::array<i64, Maxx>, Maxx>;
 
std::vector<i64> solve (int m, std::vector<P> const &pts) {
    static Mat sum;
    static Mat2 sum2;
    memset(&sum, 0, sizeof sum);
    memset(&sum2, 0, sizeof sum2);
 
    for (auto &p: pts) {
        //fprintf(stderr, "+ %d %d\n", p.x, p.y - p.x + m);
        ++sum[p.x][p.y - p.x + m];
        ++sum2[p.x][p.y];
    }
 
    for (int i = m; i >= 0; --i)
        for (int j = m * 2; j >= 0; --j) {
            sum[i][j] +=
                sum[i + 1][j] +
                sum[i][j + 1] -
                sum[i + 1][j + 1];
        }
 
    for (int i = m; i >= 0; --i)
        for (int j = m; j >= 0; --j) {
            sum2[i][j] +=
                sum2[i + 1][j] +
                sum2[i][j + 1] -
                sum2[i + 1][j + 1];
        }
 
    /*
    fprintf(stderr, "sum=\n");
    for (int i = 0; i <= m; ++i, fprintf(stderr, "\n"))
        for (int j = 0; j <= m * 2; ++j)
            fprintf(stderr, "%d ", sum[i][j]);
    fprintf(stderr, "sum2=\n");
    for (int i = 0; i <= m; ++i, fprintf(stderr, "\n"))
        for (int j = 0; j <= m * 2; ++j)
            fprintf(stderr, "%d ", sum2[i][j]);
            */
 
    auto ans = std::vector<i64>(5);
 
    for (auto &p: pts) {
        int qx = p.y, qy = p.y - p.y + m;
        i64 ru = sum[qx + 1][qy + 1],
            rd = sum[qx + 1][0] - ru,
            lu = sum[0][qy + 1] - ru,
            ld = sum[0][0] - rd - lu - ru;
        // fprintf(stderr, "= %d,%d\n", qx, qy);
        // fprintf(stderr, "> %d %d %d %d\n", ru, rd, lu, ld);
 
        if (p.x >= p.y) {
            //fprintf(stderr, "case1 %d %d %d\n", ld, rd + lu, ru);
 
            ans[1] += ld;
            ans[2] += rd + lu;
            ans[3] += ru;
 
        } else {
            i64 wtf3 =
                sum[p.x + 1][p.x - p.x + m + 1] -
                ru -
                sum2[p.x + 1][p.y + 1] +
                sum2[p.y + 1][p.y + 1];
 
            i64 wtf2 =
                sum2[0][0] -
                sum2[p.y + 1][0] -
                sum2[0][p.y + 1] +
                sum2[p.y + 1][p.y + 1] -
                wtf3;
             
            //fprintf(stderr, "! %d %d\n", wtf2, wtf3);
 
            lu = sum2[0][p.y + 1] - sum2[p.y + 1][p.y + 1];
            //fprintf(stderr, "lu=%d\n", lu);
            //fprintf(stderr, "case2 %d %d %d\n", wtf2, rd + lu + wtf3, ru);
 
            ans[2] += wtf2;
            ans[3] += rd + lu + wtf3;
            ans[4] += ru;
        }
    }
 
    return ans;
}
 
int main () {
    std::ios::sync_with_stdio(false);
 
    int n, m;
    while (std::cin >> n >> m) {
        auto pts = std::vector<P>(n);
        for (auto &p: pts)
            std::cin >> p.x >> p.y;
 
        auto ans = solve(m, pts);
        std::cout << ans[1] << ' '
                  << ans[2] << ' '
                  << ans[3] << ' '
                  << ans[4] << '\n';
    }
 
    return 0;
}

F

这题是真的。。。。有意思x
显然发现,因为至少要求3个TC,3个CF。
那么实际上你只要确定了哪3个是TC,哪3个是CF,剩下的到底是TC还是CF可以用网络流跑出来。
但是因为你要枚举哪几个是TC,哪几个是CF,这样需要 O ( n 4 ) O(n^4) O(n4)来枚举。
然后剩下这步比赛中快乐自闭2h,成功醒悟。
考虑任意3个点,里面肯定至少有2个TC,或者至少有2个CF。
那么我们可以在 O ( n 2 ) O(n^2) O(n2)枚举一侧的情况下,另一侧对于3个点假装其中两个是另一边的然后跑网络流就行了。
换句话说,2,3,4三个点,里面如果有2个是TC,那么用这两个点和你枚举的点当CF的,就可以跑出答案,如果有2个是CF,同样的也可以跑出答案。

#include <bits/stdc++.h>
using namespace std;
const int maxn=55,maxm=510,INF=0x7FFFFFFF;
struct edge { int obj,last,cap; } e[maxm<<1];
int n,m,s,t,ans,cnt,point[maxn],arc[maxn],dep[maxn],Q[maxn],x[maxm],y[maxm],z[maxm];
void add(int x,int y,int z)
{
    //cerr << x << ' ' << y << ' ' << z << '\n';
    cnt++; e[cnt].obj=y; e[cnt].last=point[x]; e[cnt].cap=z; point[x]=cnt;
    cnt++; e[cnt].obj=x; e[cnt].last=point[y]; e[cnt].cap=0; point[y]=cnt;
}
bool bfs()
{
    for (int i=s;i<=t;i++) dep[i]=0;
    //memset(dep,0,sizeof(dep));
    dep[s]=1;
    Q[1]=s;
    for (int head=1,tail=1,u;head<=tail;head++)
    {
        u=Q[head];
        for (int i=point[u],v;i;i=e[i].last)
            if (e[i].cap)
            {
                v=e[i].obj;
                if (dep[v]) continue;
                dep[v]=dep[u]+1;
                Q[++tail]=v;
            }
    }
    return dep[t];
}
int dfs(int u,int f)
{
    if (u==t || !f) return f;
    int res=0;
    for (int &i=arc[u],v,F;i;i=e[i].last)
        if (e[i].cap)
        {
            v=e[i].obj;
            if (dep[u]+1!=dep[v]) continue;
            F=dfs(v,min(f,e[i].cap));
            if (!F) continue;
            f-=F;
            res+=F;
            e[i].cap-=F;
            e[i^1].cap+=F;
            if (!f) break;
        }
    return res;
}
void solve(int A,int B,int C,int X,int Y,int Z)
{
    if (B==X || B==Y || C==X || C==Y) return;
    cnt=1;
    for (int i=s;i<=t;i++) point[i]=0;
    for (int i=1;i<=m;i++) add(x[i],y[i],z[i]);
    add(s,A,INF);
    add(s,B,INF);
    add(s,C,INF);
    add(X,t,INF);
    add(Y,t,INF);
    add(Z,t,INF);
    int res=0;
    while (bfs())
    {
        for (int i=s;i<=t;i++) arc[i]=point[i];
        res+=dfs(s,INF);
        //printf(">>>>>> %d %d %d\n",B, C, res);
    }
    ans=min(ans,res);
}
int main()
{
    while (scanf("%d%d",&n,&m)>0)
    {
        t=n+1;
        ans=INF;
        for (int i=1;i<=m;i++) scanf("%d%d%d",&x[i],&y[i],&z[i]);
        for (int i = 2; i < n; ++i)
            for (int j = 2; j < n; ++j) {
                if (i == j)
                    continue;
                solve(1, 2, 3, i, j, n);
                solve(1, 2, 4, i, j, n);
                solve(1, 3, 4, i, j, n);
                solve(1, i, j, 2, 3, n);
                solve(1, i, j, 2, 4, n);
                solve(1, i, j, 3, 4, n);
            }
        printf("%d\n",ans);
    }
    return 0;
}

G

我也不知道新队友是怎么做的。。。。我没看题。

#include <bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,m,suma,sumb,a[maxn],b[maxn];
double calc(int A,int B,double ave)
{
    return sqrt((B+m*ave*ave-2*ave*A)/(m-1));
}
int main()
{
    while (scanf("%d%d",&n,&m)>0)
    {
        suma=0;
        sumb=0;
        for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]*a[i];
        for (int i=1;i<=m;i++) suma+=a[i],sumb+=b[i];
        printf("%.8lf\n",calc(suma,sumb,(double)suma/m));
        for (int i=m+1;i<=n;i++)
        {
            suma=suma-a[i-m]+a[i];
            sumb=sumb-b[i-m]+b[i];
            printf("%.8lf\n",calc(suma,sumb,(double)suma/m));
        }
    }
    return 0;
}

H

同样我也不知道他是怎么做的。。。比赛的时候没来看他。

#include <bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,m,a[maxn],b[maxn];
long long ans;
int main()
{
    a[0]=-1;
    b[0]=-1;
    while (scanf("%d%d",&n,&m)>0)
    {
        ans=0;
        for (int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n);
        for (int i=1;i<=m;i++) scanf("%d",&b[i]); sort(b+1,b+1+m);
        for (int i=1,x,y,lastx,lasty;i<=n;i++)
        {
            x=lower_bound(b+1,b+1+m,a[i])-b-1;
            y=upper_bound(b+1,b+1+m,a[i])-b;
            //printf("%d %d\n",x,y);
            while (x>=1)
            {
                lastx=x;
                long long dec=sqrt(a[i]-b[x]),tmp;
                tmp=(dec+1)*(dec+1);
                x=upper_bound(b+1,b+1+m,a[i]-tmp)-b;
                ans+=dec*(lastx-x+1);
                x--;
            }
            while (y<=m)
            {
                lasty=y;
                long long dec=sqrt(b[y]-a[i]),tmp;
                tmp=(dec+1)*(dec+1);
                y=lower_bound(b+1,b+1+m,a[i]+tmp)-b-1;
                ans+=dec*(y-lasty+1);
                y++;
            }
        }
        printf("%lld",ans);
    }
    return 0;
}

I

J

显然这个就是你来安排一个顺序,但是你考虑一条边的贡献,这条边肯定是哪个大,哪边就先删,那么对应n-1个大小关系,肯定是可以做到的。
实际上最后就是从大到小删就行。

#include <iostream>
#include <cstdio>
 
using namespace std;
 
int main() {
    ios::sync_with_stdio(0);
    static int a[100005];
    int n;
    while (cin >> n) {
        for (int i = 1; i <= n; ++i)
            cin >> a[i];
        long long ans = 0;
        for (int i = 1; i < n; ++i) {
            int x, y;
            cin >> x >> y;
            ans += min(a[x], a[y]);
        }
        cout << ans << '\n';
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值