The 12th Undergraduate Program Design Competition of Zhejiang University of Traditional Chinese Medicine

Problem A. Jhadgre's C language program

Attention is helle

Problem B. Wpremig's AH battle

The Bash game is discussed in three situations.
When m<=n, you can win right from the start.
When m>n and m%(n+1) == 0, the first move must be defeated.
When m>n and m%(n+1) != 0, you only need to take m% (n + 1) first.

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

int m, n;

int main()	
{
	while (scanf("%d%d", &n, &m) != EOF)
	{
		if (m % (n + 1) == 0)
			puts("You are loser");
		else if (n >= m)
		{
			for (int i = m; i < n; i ++)
				printf("%d ", i);
			printf("%d\n", n);
		}
		else
			printf("%d\n", m % (n + 1));
	}
	return 0;
}

Problem C. Wpremig's triangle

Divide the triangle into rectangles with width d and sort them from high to low, then we must choose the first L/d rectangles to be optimal in the area, then after infinitely dividing the rectangle, suppose the height of the last rectangle we choose is H , Then for a triangle with a height greater than H, there must be a rectangle with a height H belonging to the triangle that has been selected. Then for all triangles with height greater than H, the part with height H must be placed in the area, that is, the height of the intersection is H.
Conclusion:
1. The shortest side is placed on the x-axis;
2. When the side placed on the x-axis is determined, the optimal solution satisfies the intersection of all triangles on a straight line parallel to the x-axis

With the above conclusions, it is obvious that the higher the triangle, the easier it is to choose, so the higher the triangle, the better.
With this conclusion, the height of the bisection point can easily solve this problem

#include <cstdio>
#include <cmath>
using namespace std;
const double eps = 1e-8;
const int maxn = 100010;

int T, cas = 1, n;
double r, a[maxn], b[maxn], c[maxn];
double area[maxn], height[maxn];

double f(double h)
{
    double ret = 0;
    for (int i=1;i<=n;i++)
        if (h < height[i]) ret += a[i] * (1.0 - h / height[i]);
    return ret;
}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d%lf", &n, &r);
        for (int i=1;i<=n;i++) scanf("%lf%lf%lf", &a[i], &b[i], &c[i]);
        for (int i=1;i<=n;i++)
        {
            double p = (a[i] + b[i] + c[i]) / 2;
            area[i] = sqrt(p * (p-a[i]) * (p-b[i]) * (p-c[i]));
            height[i] = area[i] * 2 / a[i];
        }
        double low = 0, high = 1000000, mid;
        while ( fabs(high - low) > eps )
        {
            mid = (low + high) / 2;
            if (f(mid) <= r) high = mid;
            else low = mid;
        }
        double ans = 0, h = mid;
        for (int i=1;i<=n;i++)
            if (h < height[i]) ans += a[i] * (1.0 - h / height[i]) * (height[i] - h) / 2;
        printf("%.3lf\n", ans + h * r);
    }
    return 0;
}

Problem D. Jhadgre's Ladder

Sent, note that the data range is just larger than int, not INT_MAX

#include <bits/stdc++.h>
using namespace std;

int main()
{
	long long n,l;
	cin>>n>>l;
	long long ans = l;
	for (int i = 0 ; i < n ; ++i) {
		long long x;cin>>x;
		if (x > ans) ans = x;
	}
	cout<<ans - l<<endl;
	return 0;
} 

Problem E. Jhadgre's chorus formation

Originally I wanted to make the tree set tree to be able to pass... However, the time limit and space limitation of the title are more awkward, so I simply changed it to the overall dichotomy.

First consider if you only ask once, then suppose the order of the question is k, we can divide the answer mid, each check is to traverse all the modifications, build a tree array, for an operation of adding a number z to the [x,y] interval, If z>=mid, then give +1 to the entire interval of [a,b]. Finally, the sum of the query interval, that is, the number of numbers >= mid in this interval. If this number >=k, then divide up by two and record the answer, otherwise divide down by two

We can find that the most time consuming place is maintenance, and the maintenance operation is only related to mid, and has nothing to do with specific queries. Therefore, consider processing the queries, and put all the queries that need to be "upward dichotomy" (ie [mid+1,r]) and "downward dichotomy" queries (ie [l,mid]) into a set each time, Of course, at the same time, the changes that may affect them should also be added to the collection following the query, and then the operation will continue recursively separately.

For a query, if the sum of the query interval is greater than or equal to the ranking of the query, the query is divided into the "upward dichotomy" set, otherwise it is divided into the "downward dichotomy" set.

For the modification, if the number added by a modification is <=mid, then it must not contribute to the query that has been determined to be answered in [mid+1,r], so it only needs to be added to the set of "downward dichotomy";
otherwise So this modification must have contributed to the query of the interval [l,mid]. If you subtract 1 from the ranking of the question in [l,mid], this modification will only contribute to the inquiries in the "up dichotomy" set, so add this modification to the "up dichotomy" In the collection.

As for the number of them, just use BIT to maintain it, interval update + interval query.

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define MAXN 50005
typedef long long LL;
using namespace std;
int n,m,id[MAXN],t1[MAXN],t2[MAXN],T=0;
LL ans[MAXN];

LL read(){
    LL x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';c=getchar();
    }
    return x*f;
}

struct Node1{
    int opt,a,b;
    LL c;
}O[MAXN];
struct BIT{
    LL c[MAXN];int sign[MAXN];
    int lowbit(int x){return x&-x;}
    void add(int pos,int x){
        while(pos<=n){
            if(sign[pos]!=T)c[pos]=0,sign[pos]=T;
            c[pos]+=x,pos+=lowbit(pos);
        }
    }
    LL query(int pos){
        LL res=0;
        while(pos>0){
            if(sign[pos]!=T)c[pos]=0,sign[pos]=T;
            res+=c[pos],pos-=lowbit(pos);
        }
        return res;
    }
}c1,c2;

void ADD(int a,int b){
    c1.add(a,1),c1.add(b+1,-1);
    c2.add(a,a),c2.add(b+1,-b-1);
}
LL QUERY(int a,int b){
    LL res=0;
    res+=(b+1)*c1.query(b)-c2.query(b);
    res-=a*c1.query(a-1)-c2.query(a-1);
    return res;
}
void solve(int l,int r,int ansl,int ansr){
    if(l>r)return;
    if(ansl==ansr){
        for(int i=l;i<=r;i++)
        if(O[id[i]].opt==2)ans[id[i]]=ansl;
        return;
    }
    int mid=(ansl+ansr)>>1;
    int j=1,k=1;
    T++;
    for(int i=l;i<=r;i++){
        int idx=id[i];
        if(O[idx].opt==1){
            if(O[idx].c<=mid)t1[j++]=idx;
            else t2[k++]=idx,ADD(O[idx].a,O[idx].b);
        }
        else{
            LL res=QUERY(O[idx].a,O[idx].b);
            if(res>=O[idx].c)t2[k++]=idx;
            else t1[j++]=idx,O[idx].c-=res;
        }
    }
    --j,--k;
    for(int i=1;i<=j;i++)id[l+i-1]=t1[i];
    for(int i=1;i<=k;i++)id[l+j+i-1]=t2[i];
    solve(l,l+j-1,ansl,mid),solve(l+j,r,mid+1,ansr);
}

int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++){
    	O[i].opt=read();
		O[i].a=read();
		O[i].b=read();
		O[i].c=read();
		id[i]=i;
	}
    solve(1,m,-n,n);
    for(int i=1;i<=m;i++)
    	if(O[i].opt==2)
			printf("%d\n",ans[i]);
    return 0;
}

Problem F. Jhadgre's sad

Recursion, small dp, just write casually.

#include <bits/stdc++.h>
using namespace std;
int n;
int a[100000];
int fun(int x){
	if (x > n) return 0;
	return min(fun(a[x]),fun(x + 5)) + 1;
}

int main()
{
	scanf("%d",&n);
	for (int i = 1 ; i <= n ; ++i)
		scanf("%d",&a[i]);
	cout<< fun(1) * 2<<endl; 
	return 0;
} 

Problem G. Wpremig's weighing problem

First, give a conclusion: if you need to find balls of different quality and know the weight for y times, the maximum number of balls that can be weighed is n = (3 k − 3) / 2 (3^k-3)/2(3k3)/2

The proof idea is as follows, and the lemma is proved in turn:
Lemma 1:
If there are m balls or standard or heavier than the standard, and n balls are either standard or lighter than the standard and at least one standard ball, then k times of weighing can be The necessary and sufficient condition for determining which ball is: m + n ≤ 3 k m+n≤3^km+n3k

Lemma 2:
If there are n balls that do not know whether they are standard weight, lighter or heavier, and at least one standard ball, the necessary and sufficient condition for k times to determine which ball is: n ≤ 1/2 ( 3 k + 1) n≤1/2(3^k+1)n1/2(3k+1)

Lemma 3:
If there are n balls without knowing whether it is a standard weight, lighter or heavier, and at least one standard ball, then k times of weighing can determine which ball is and whether the ball is lighter or heavier. The essential condition is: n ≤ 1/2 (3 k − 1) n≤1/2(3^k−1)n1/2(3k1) The
idea to prove the sufficiency of Lemma 1 is:
Letm = 3 i + j, n = 3 k + rm=3i+j, n=3k+rm=3 i+j,n=3 k+r . Put i on each side which may be heavy and k which may be light, and then j, r=0, 1, 2 for a total of 9 possibilities. Discuss the classification and discuss it recursively.
The necessity is obvious.
The idea of ​​proof of the sufficiency of Lemma 2 is:
(3 k + 1) / 2 (3^k+1)/2(3k+1 ) / 2 balls, the first time(3 k − 1 + 1) / 2 (3^{k-1}+1)/2(3k1+1 ) / 2 balls on the left,(3 k − 1 − 1) / 2 (3^{k-1}-1)/2(3k11 ) / 2 balls plus the standard ball on the right, the remaining(3 k − 1 + 1) / 2 (3^{k-1}+1)/2(3k1+1 ) / 2 After the first weighing, either balance can be proved by recursion, or imbalance can be proved by lemma.
The sufficiency proof of Lemma 3 has the same idea, the difference lies in the remaining(3 k − 1 − 1) / 2 (3^{k-1}-1)/2(3k11 ) / 2 balls.
The idea of ​​proof of the necessity of Lemma 3 is the same as that of question 2 above
. The comparative proof of Lemma 2 is more troublesome, but the idea is still similar. If the first weighing is unbalanced, use Lemma 1, and if it is balanced, recursively.
In the end, the proof of the two problems needs to be discussed separately for the first weighing, because there is no standard ball to borrow, and the number is one less than the lemma, and then you can use the conclusion of the lemma to prove through similar ideas.

#include <bits/stdc++.h>
using namespace std;
int main(){
	int x,y;
	while (~scanf("%d%d",&x,&y)){
		if (x <= 2){
			puts("No");
			continue;
		}
		long long now = 3;
		int k;
		for (k = 2 ; k < 15 ; ++k){
			now *= 3;
			if ((now-3)/2 >= x) break;
		}
		if (k <= y) puts("Yes");
		else puts("No");
	}
	return 0;
} 

Problem H. Jhadgre's way home

Obviously, it is difficult to search according to the path of "L"→"W"→"Q" because it is necessary to first go to each "W" and then search for the shortest path to "Q" from "W", but this path can be imagined It becomes "L"→"W"←"Q", so you don't need to consider "W".
So two times of bfs, starting from "L" and starting from "Q", and then traversing each "W", the sum of the shortest paths from "L" and "Q" to this point is the key The shortest way back to the bedroom, just ask for the shortest one.

Or two times of bfs, starting from "L" and "Q" respectively, do two bfs, and then traverse the entire map to judge the shortest path for all "W"

#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 2010;
const int INF = 0x3f3f3f3f;

int n, m;
int vis[MAXN][MAXN];
int ret[2][MAXN][MAXN];
char a[MAXN][MAXN];
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};

void bfs(int xxx, int yyy, int d) {
	queue< pair<int, int> > q;
	q.push(make_pair(xxx, yyy));
	vis[xxx][yyy] = 1;
	ret[d][xxx][yyy] = 0;
	while(!q.empty()) {
		int tx = q.front().first;
		int ty = q.front().second;
		q.pop();
		for (int i = 0;i < 4; ++i) {
			int x = tx + xx[i];
			int y = ty + yy[i];
			if (x >= 0 && x < n && y >= 0 && y < m && a[x][y] != '#' && !vis[x][y]) {
				ret[d][x][y] = ret[d][tx][ty] + 1;
				vis[x][y] = 1;
				q.push(make_pair(x, y));
			}
		}
	}
}

int main() {
	while (~scanf("%d %d", &n, &m)){
		queue< pair<int, int> > q;
		memset(ret, INF, sizeof(ret));
		memset(vis, 0, sizeof(vis));
		int sx, sy;
		int tx, ty;
		for (int i = 0;i < n; ++i) {
			scanf("%s", a[i]);
			for (int j = 0;j < m; ++j) {
				if (a[i][j] == 'W') {
					q.push(make_pair(i, j));
				} else if (a[i][j] == 'L') {
					sx = i;
					sy = j;
				} else if (a[i][j] == 'Q') {
					tx = i;
					ty = j;
				}
			}
		}
		bfs(sx, sy, 0);
		memset(vis, 0, sizeof(vis));
		bfs(tx, ty, 1);
		int ans = INF;
		while(!q.empty()) {
			int x = q.front().first;
			int y = q.front().second;
			q.pop();
			ans = min(ans, ret[0][x][y] + ret[1][x][y]);
		}
		printf("%d\n", ans);
	}
	return 0;
}

Problem I. Jhadgre's cookies

Send the title, string.find()

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int N;scanf("%d",&N);
	int ans = 0 ;
	while (N--){
		string x;cin>>x;
		if (x.find("zailaiyihe") != string::npos){
			ans++;
		} 
	} 
	cout<<ans<<endl;
	return 0;
} 

Problem J. Jhadgre climbing stairs

Double for loop is enough ...note that the modulo is not 1 e 9 + 7 1e9+71e9+7 1 e 8 + 7 1e8+7 1e8+7

#include <iostream>
#include <cstdio>
using namespace std;
const int mod = 100000007;
int dp[10100];
int main() {
	int n;
    dp[0] = 1;
    for (int i = 1; i <= 10000; ++i) {
        dp[i] = dp[i - 1];
        for (int j = i - 2; j >= 0; j -= 2) {
            dp[i] += dp[j];
            dp[i] %= mod;
        }
    }
    while (cin>>n)
    	cout << dp[n] << endl;
    return 0;
}

Problem K. Jhadgre的π

BBP公式或者各种收敛方式都可以。
http://www.huanqiujiemi.com/7xqE25x.html
参考图…日本发行的一本书

#include <cstdio>
#include <cmath>
#include <iostream>
#define MAX_C 56000
int a = 10000, b, c = MAX_C, d, e, f[MAX_C + 1], g, n, ans, cnt;
using namespace std;

int main()
{
	int pp;
    scanf("%d", &n);
    a = 10000;
	b = d = e = g = ans = cnt = 0;
	c = MAX_C; 
	for (; b - c; ) f[b++] = a / 5;
    for (; d = 0, g = c * 2; c -= 14, ans = e + d / a, e = d % a, cnt++) {
        if (cnt * 4 > n) break;
        for (b = c; d += f[b]*a, f[b] = d % --g, d /= g--, --b; d *= b);
    }
    if (n % 4 == 0) cout << (ans / 1000);
    else if (n % 4 == 1) cout << ((ans / 100) % 10);
    else if (n % 4 == 2) cout << ((ans / 10) % 10);
    else if (n % 4 == 3) cout << (ans % 10);
    cout<<endl;
	return 0;
}

Problem L. Wpremig’s Niuniu

英语阅读题
先用一个五维数组预处理出所有可能的得分,然后在求每一组数据的时候直接求和再/13即可。注意四舍五入。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

inline void read(int &x)
{
    x = 0;char ch = getchar(), c = ch;
    while(ch < '0' || ch > '9')c = ch, ch = getchar();
    while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
    if(c == '-')x = -x;
}

inline int min(int a,int b)
{return a<b?a:b;}

int ans[15][15][15][15][15];
int x,y,m,n,z,sum;

inline void init()
{
    for(int a = 1;a <= 13;++ a)
        for(int b = 1;b <= 13;++ b)
            for(int c = 1;c <= 13;++ c)
                for(int d = 1;d <= 13;++ d)
                    for(int e = 1;e <= 13;++ e)
    {
        if(a<5 && b<5 && c<5 && d<5 && e<5 && a+b+c+d+e <= 10)
            ans[a][b][c][d][e] = 60;
        else if(a>10 && b>10 && c>10 && d>10 && e>10)
            ans[a][b][c][d][e] = 50;
        else if((a==b && b==c && c==d) || (a==b && b==c && c==e) || (a==b && b==d && e==d) || (a==e && e==c && c==d) || (e==b && b==c && c==d))            
            ans[a][b][c][d][e] = 40;
        else
        {
            x = min(a,10),y = min(b,10),m = min(c,10),n = min(d,10),z = min(e,10);
            if((x+y+m)%10 == 0 || (y+m+n)%10 == 0 || (m+n+z)%10 == 0 || (x+y+n)%10 == 0 || (x+y+z)%10 == 0 || (y+m+z)%10 == 0 || (y+n+z)%10 == 0 || (x+n+z)%10 == 0 || (x+m+n)%10 == 0 || (x+m+z)%10 == 0)
            {
                sum = x+y+m+n+z;
                if(sum%10 == 0)
                    ans[a][b][c][d][e] = 30;
                else if(sum%10 < 7)
                    ans[a][b][c][d][e] = sum%10;
                else
                    ans[a][b][c][d][e] = (sum%10)*2;
            }
        }
    }
}

int main()
{
    init();
    int t;
    read(t);
    for(;t;--t)
    {
        sum = 0;
        read(x),read(y),read(m),read(n);
        for(register int i = 1;i <= 13;++ i)
            sum += ans[x][y][m][n][i];
        sum = (sum/13.0)+0.5;
        printf("%d\n",sum);
    }
    return 0;
}

Problem M. Wpremig和Jhadgre的藏宝图

对图进行黑白染色
设黑色格子的数量为 black
设白色格子的数量为 white
设黑色格子的数值和为 sumblack
设白色格子的数值和为 sumwhite

设最后每个格子的数字都变为x则
black * x – sumblack = white * x – sumwhite
x = (sumblack – sumwhite) / (black– white)

1.当black ≠ white时 可以解出 x 再用网络流check
2.当black = white时 ,可以发现 对于一个合法的x, k>=x都是一个合法的解
因为black = white => (black + white) % 2 == 0 可以构造一层的满覆盖
所以可以二分x 然后用网络流check

For check
construction:
if the point k is white, create an edge (s, k, x – v[k])
if the point k is black, create an edge (k, t, x – v[k])
to the adjacent point u , V (u is white), build an edge (u, v, inf) to
determine whether the flow is full.

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int s=1690,t=1691;
const LL oo2=1e17,oo1=1e13,oo3=1e15;
int a[50][50],num[50][50],xx[]={0,0,1,-1},yy[]={1,-1,0,0},
fir[1700],ne[10010],to[10010],que[1700],f[1700],
m,n,tot;
LL w[10010];
bool ok(int x,int y)
{
    return x>=1&&x<=n&&y>=1&&y<=m;
}
void init()
{
    int i,j;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
        scanf("%d",&a[i][j]);
}
void add(int u,int v,LL x)
{
    tot++;
    ne[tot*2]=fir[u];
    fir[u]=tot*2;
    to[tot*2]=v;
    w[tot*2]=x;
    ne[tot*2+1]=fir[v];
    fir[v]=tot*2+1;
    to[tot*2+1]=u;
    w[tot*2+1]=0;
}
bool find()
{
    int hd=1,tl=1,i,u,v;
    que[1]=s;
    memset(f,0,sizeof(f));
    f[s]=1;
    while (hd<=tl)
    {
        u=que[hd++];
        for (i=fir[u];i;i=ne[i])
          if (w[i]&&!f[v=to[i]])
          {
            f[v]=f[u]+1;
            que[++tl]=v;
          }
    }
    return f[t];
}
LL dfs(int u,LL lim)
{
    int i,v;
    LL ret=0,x;
    if (u==t) return lim;
    for (i=fir[u];i&&ret<lim;i=ne[i])
      if (w[i]&&f[v=to[i]]==f[u]+1)
      {
        x=dfs(v,min(lim-ret,w[i]));
        ret+=x;
        w[i]-=x;
        w[i^1]+=x;
      }
    if (!ret) f[u]=0;
    return ret;
}
bool ok(LL x)
{
    int i,j,kk,x1,y1;
    tot=0;
    memset(fir,0,sizeof(fir));
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
        if (i+j&1) add(s,num[i][j],x-a[i][j]);
        else add(num[i][j],t,x-a[i][j]);
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
        if (i+j&1)
          for (kk=0;kk<4;kk++)
            if (ok(x1=i+xx[kk],y1=j+yy[kk]))
              add(num[i][j],num[x1][y1],oo3);
    while (find())
    {
        int xxx;
        xxx=1;
        while (dfs(s,oo2));
    }
    for (i=fir[s];i;i=ne[i])
      if (w[i]) return 0;
    return 1;
}
void solve1()
{
    int i,j;
    LL s0=0,s1=0,x;
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
        if (i+j&1) s1+=a[i][j];
        else s0+=a[i][j];
    x=s0-s1;
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
        if (a[i][j]>x)
        {
            printf("-1\n");
            return;
        }
    if (!ok(x)) printf("-1\n");
    else printf("%lld\n",(x*m*n-s0-s1)/2);
}
void solve0()
{
    int i,j;
    LL s0=0,s1=0,x,l,r,mid;
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
        if (i+j&1) s1+=a[i][j];
        else s0+=a[i][j];
    if (s0!=s1)
    {
        printf("-1\n");
        return;
    }
    l=0;
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
        l=max(l,(LL)a[i][j]);
    r=oo1;
    while (l<r)
    {
        mid=(l+r)/2;
        if (ok(mid)) r=mid;
        else l=mid+1;
    }
    if (l==oo1) printf("-1\n");
    else printf("%lld\n",(l*m*n-s0-s1)/2);
}
int main()
{
    int T,i,j;
    for (i=1;i<=40;i++)
      for (j=1;j<=40;j++)
        num[i][j]=i*40+j;
    scanf("%d",&T);
    while (T--)
    {
        init();
        if (m*n&1) solve1();
        else solve0();
    }
}

Guess you like

Origin blog.csdn.net/jnxxhzz/article/details/85211569