ZUST 集训队菜鸡互啄-5

A- Roads not only in Berland
题目大意:给你N个点和N-1条边,每次操作要隐藏一条边和增加一条边,问最少第几次操作时N个城市可以互相到达
可以考虑并查集合并时判断环,答案就是环的个数。判断到环时记录环上一条边为隐藏边,要添加的边就是根结点与根节点直接的边。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int fa[maxn],r[maxn],l[maxn],t[maxn];
int find(int x)
{
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]); 
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)fa[i]=i;
    int x,y,cnt=0,ans=0;
    for(int i=1;i<n;i++)
    {
        cin>>x>>y;
        int fx=find(x);
        int fy=find(y);
        if(fx==fy)
        {
            cnt++;
            l[cnt]=x;
            r[cnt]=y;
        }
        else fa[fx]=fy;
    }
    for(int i=1;i<=n;i++)
    {
        if(find(i)==i)ans++,t[ans]=i;
    }
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++)
    {
        printf("%d %d %d %d\n",l[i],r[i],t[i],t[i+1]);
    }
    return 0;
}

B-Unordered Subsequence
签到题,找最小不规则子序列。可看出 有解时最小必定是3.

#include <bits/stdc++.h>
using namespace std;
long long n, a[100010], m = 0;
int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 0; i < n - 1; i++)
        if ((a[i] - a[0]) * (a[i + 1] - a[i]) < 0)
        {
            cout << 3 << endl
                 << 1 << " " << i + 1 << " " << i + 2 << endl;
            return 0;
        }
    cout << 0;
}

C-Wooden Fence
题目大意:一个人要修建篱笆,找了一家木篱笆公司买木板。这个公司若干种类的木板,并且仓库足够大,所以每种种类的木板数量可以看做无限大。现在这个人从这个公司买回若干种类的木板若干块。一块木板的种类由它的长和宽决定。不同的长宽表示不同的木板种类。现在这个人想尽可能构建出漂亮的篱笆,漂亮的篱笆,有两个条件
1 不允许有连续两个以上的相同种类的木板
2 下一块模板的长度要等于上一块木板的宽度
木板可以旋转,长宽互换。现在给出木板的种类数目(块数)和要构建篱笆的长度。问有多少种排列方式可以构建出漂亮的篱笆。最后的答案非常大,需要mod 1e9+7。
输入的N代表的是木板的种类,这两块木板出现在下面的输入数据中,说明这两块木板应该看做不同种类的木板,只有一块木板旋转以后才看做相同的木板。然后就可以用DP做了。构建一个DP数组【i】【j】代表当前已经构建了长度为i的篱笆,最后一块木板是j的方案总数。开始dp数组清零。开始的时候处理每一块木板,然后对应的木板加1;然后开始循环。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e3+110;
const int mod=1e9+7;
int dp[maxn][310];
int a[310],b[310];
int main()
{
    int l,n,x,y,ans=0;
    cin>>n>>l;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i]>>b[i];
        dp[a[i]][i]++;
        if(a[i]!=b[i])
        {
            a[i+n]=b[i];
            b[i+n]=a[i];
            dp[a[i+n]][i+n]++;
        }
    }
    for(int i=1;i<=l;i++)
    {
        for(int j=1;j<=n*2;j++)
        {
            if(!dp[i][j])continue;
            for(int k=1;k<=n*2;k++)
            {
                if((j%n)!=(k%n) && b[j]==a[k])dp[i+a[k]][k]=(dp[i+a[k]][k]+dp[i][j])%mod;
            }
        }
    }
    for(int i=1;i<=2*n;i++)ans=(ans+dp[l][i])%mod;
    cout<<ans<<endl;
    return 0;
}

D-Headquarters
假签到 画画图找规律,找到真签到

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	long long a = 1, b = 1;
	string s;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> s;
		if (s == "UL" || s == "DR")
			a++;
		else if (s == "UR" || s == "DL")
			b++;
		else
			a++, b++;
	}
	cout << a * b << endl;
	return 0;
}

E-Zoo
题意:有n个望远镜,被放置在X轴1~n的位置上,现有m只鸟,望远镜可以以任何角度观察,能看到在那条直线上的所有鸟,
问所有望远镜能看到的鸟的数量之和
计算几何+暴力

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
typedef long long int ll;
int n, m;
int num[maxn];
struct line
    ll a,
    b, c;
}
;
struct point
{
    ll x, y;
} niao[300];
line ppline(point p1, point p2)
{
    line l;
    l.a = p2.y - p1.y;
    l.b = p1.x - p2.x;
    l.c = p1.y * p2.x - p1.x * p2.y;
    return l;
}
int online(point p, line l)
{
    if (p.x * l.a + p.y * l.b + l.c == 0)
        return 1;
    return 0;
}
int xofline(int y, line l)
{
    if (l.a == 0)
        return -1;
    if (l.c % l.a != 0)
        return -1;
    double ret;
    ret = -(l.c * 1.0 / l.a);
    if (ret > 1000099 || ret < 0)
        return -1;
    return -l.c / l.a;
}
int main()
{
    int i, j, k, ret;
    scanf("%d%d", &n, &m);
    memset(num, 0, sizeof(num));
    for (i = 1; i <= m; ++i)
        scanf("%lld%lld", &niao[i].x, &niao[i].y);
    for (i = 1; i <= m; i++)
    {
        for (j = i + 1; j <= m; j++)
        {
            line l = ppline(niao[i], niao[j]);
            int you = 2;
            for (k = j + 1; k <= m; ++k)
            {
                if (online(niao[k], l))
                    you++;
            }
            int x = xofline(0, l);
            if (x >= 1 && x <= n && num[x] < you)
                num[x] = you;
        }
    }
    ret = 0;
    for (i = 1; i <= n; ++i)
        if (num[i])
            ret += num[i];
        else
            ret += 1;
    printf("%d\n", ret);
    return 0;
}

F-
题目大意:n个点,m辆车,r轮比赛,两点之间使用不同的车消耗不同的时间,每轮比赛给出a,b,c表示从a走到b最多允许转换c次车,问每轮比赛的最短时间
(1)以允许转换车的次数进行dp,dp[i][j][k]表示做多允许转换i次车,从j走到k所需的最短时间; dp[i][j][k]=min(dp[i-1][j][h]+dp[0][h][k]);
(2)在一条路径上最多转换n-1次车;

#include<bits/stdc++.h>
using namespace std;
const int maxn=70;
int cost[maxn][maxn][maxn],dp[maxn*20][maxn][maxn];
const int inf=0x3f3f3f3f;
int main()
{
    int n,r,x,y,k,m;
    scanf("%d%d%d",&n,&m,&r);
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
            for(k=1;k<=n;k++)scanf("%d",&cost[i][j][k]);
        for(k=1;k<=n;k++)
            for(x=1;x<=n;x++)
                for(y=1;y<=n;y++)cost[i][x][y]=min(cost[i][x][y],cost[i][x][k]+cost[i][k][y]);
    }
    for(int i=0;i<=1001;i++)
        for(int j=1;j<=n;j++)
            for(k=1;k<=n;k++)dp[i][j][k]=inf;

    for(int i=1;i<=m;i++)
        for(k=1;k<=n;k++)
            for(x=1;x<=n;x++)
                for(y=1;y<=n;y++)
                    dp[0][x][y]=min(dp[0][x][y],cost[i][x][k]+cost[i][k][y]);
    for(int i=1;i<n;i++)
        for(k=1;k<=n;k++)
            for(x=1;x<=n;x++)
                for(y=1;y<=n;y++)
                    dp[i][x][y]=min(dp[i][x][y],dp[i-1][x][k]+dp[0][k][y]);
    for(int i=1;i<=r;i++)
    {
        scanf("%d%d%d",&x,&y,&k);
        int ans=inf;
        k=min(n,k);
        for(int i=0;i<=k;i++)ans=min(ans,dp[i][x][y]);
        printf("%d\n",ans);
    }
    return 0;
}

G-Non-Secret Cypher
题目大意:给出n个元素的数列(n<=4e5),问有多少个子区间满足至少有一个数值出现至少K次。
就是先找到一个符合条件的区间[l,r]记为尺子,然后用哈希记录下该区间各个值的情况,然后将尺子右移,对尺子两端的数据进行增减,判断是否满足k,不满足尺子右端伸长到满足为止,对于每一次符合条件的情况,答案ans应该加上n-r,累加下来就是答案

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
int main()
{
    ll ans=0,r=0;
    map<ll,ll> pre;
    map<ll,ll> next;
    map<ll,ll> lma;
    map<ll,ll> mp;
    int n,a,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a);
        mp[a]++;
        if(pre[a]!=0)next[pre[a]]=i;
        pre[a]=i;
        if(lma[a]==0)lma[a]=i;
        if(mp[a]==k)
        {
            r=max(r,lma[a]);
        }
        if(mp[a]>k)
        {
            lma[a]=next[lma[a]];
            r=max(r,lma[a]);
        }
        ans+=r;
    }
    printf("%lld\n",ans);
    return 0;
}

H-Two Paths
去掉一条边 剩下的2棵树的直径 乘积 求最大
列举每条边 2次bfs求直径 其实总共是 4*(n-1) 次bfs

#include<bits/stdc++.h>
using namespace std;
const int maxn=210;
int dis[maxn];
struct node
{
    int x,y;
}e[maxn];
bool mp[maxn][maxn];
int n;

int bfs(int u)
{
    memset(dis,0,sizeof(dis));
    dis[u]=1;
    queue<int> q;
    q.push(u);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(int i=1;i<=n;i++)
        {
            if(mp[u][i] && !dis[i])
            {
                dis[i]=dis[u]+1;
                q.push(i);
            }
        }
    }
    int tmp=0;
    for(int i=1;i<=n;i++)if(dis[tmp]<dis[i])tmp=i;
    memset(dis,0,sizeof(dis));
    dis[tmp]=1;
    q.push(tmp);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(int i=1;i<=n;i++)
        {
            if(mp[u][i] && !dis[i])
            {
                dis[i]=dis[u]+1;
                q.push(i);
            }
        }
    }
    tmp=0;
    for(int i=1;i<=n;i++)tmp=max(tmp,dis[i]);
    return tmp-1;
}
int main()
{
    int ans=0;
    cin>>n;
    for(int i=1;i<n;i++)
    {
        cin>>e[i].x>>e[i].y;
        mp[e[i].x][e[i].y]=mp[e[i].y][e[i].x]=true;
    }
    for(int i=1;i<n;i++)
    {
        mp[e[i].x][e[i].y]=mp[e[i].y][e[i].x]=false;
        int l1=bfs(e[i].x);
        int l2=bfs(e[i].y);
        ans=max(ans,l1*l2);
        mp[e[i].x][e[i].y]=mp[e[i].y][e[i].x]=true;
    }
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值