这场就没有那么难受了。。。。
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';
}
}