22ccpc桂林E - Draw a triangle 向量求三角形面积,exgcd

142 篇文章 1 订阅
92 篇文章 0 订阅

295B - Greg and Graph floyd

由于对Floyd的本质还是不大清楚所以做这个题还是费了点功夫,可以把整个过程反过来,就变成了解锁每个点对当前已有点的影响,其实这样也就相当于一个floyd了,值得注意的是虽然有的点没有解锁,但是是可以参与转移的,只不过累加和的时候不能加上他,为什么可以参加转移呢?因为最开始的那个k循环实际的意义就是将k这个点作为中转点来更新i和j的最短路,k是被解锁的,所以如果i和j通过k转移也是合法的,这样还不会漏掉情况

题解 P1119 【灾后重建】 - Time_Rune 的博客 - 洛谷博客 (luogu.com.cn)

#include <bits/stdc++.h>
using namespace std;
#define int long long
//const int mod=1e9+7;
const int inf=1e18;
const int N = 2e6+100;
int n,g[505][505],a[505][505],ans[505],b[505],vis[505];
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //cout<<(1LL<<19)<<endl;
    cin>>n;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        cin>>a[i][j];
        g[i][j]=a[i][j];
    }
    for(int i=1;i<=n;i++) cin>>b[i],vis[i]=0;
    for(int k=n;k>=1;k--)
    {
        vis[b[k]]=1;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            g[i][j]=min(g[i][j],g[i][b[k]]+g[b[k]][j]);
           // if(k==2&&i==3&&j==4) cout<<g[i][j]<<" jjj "<<i<<" "<<j<<" "<<g[i][b[k]]<<" "<<g[b[k]][j]<<" "<<b[k]<<endl;
        }

        int res=0;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            //if(k==2) cout<<g[i][j]<<" "<<i<<" "<<j<<endl;
            if(vis[i]&&vis[j]) res+=g[i][j];
        }
        ans[k]=res;
    }
    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
    system("pause");
    return 0;
}

/*
4
0 57148 51001 13357
71125 0 98369 67226
49388 90852 0 66291
39573 38165 97007 0
2 3 1 4
*/

D - Range and Partition 构造,双指针

最关键的是找到合适的x,y,先假设已经找到了,考虑如何输出,设in为在值域里面的数的个数,out为不在的个数,那么只要in==out+1了就可以输出这个区间,最后一段直接输出就可以,一定是满足条件的,然后可以发现前k-1段都是in==out+1,后面那一段in>=out+1,所以总的就是in>=out+k,所以就可以按照这个条件去枚举了,可以双指针也可以二分

Codeforces Round #768 (Div. 2) D(二分答案/双指针) - 知乎 (zhihu.com)

#include <bits/stdc++.h>
using namespace std;
#define int long long
//const int mod=1e9+7;
const int inf=1e18;
const int N = 2e6+100;
int t,n,k,a[N],sum[N],tx[N];
bool check(int l,int r)
{
    return (2LL*(sum[r]-sum[l-1])-n>=k);
    
}
void print(int x,int y)
{
    int in=0,out=0,l=1,cnt=1;
    for(int i=1;i<=n&&cnt<k;i++)
    {
        if(a[i]>=x&&a[i]<=y) in++;
        else out++;
        if(in>out)
        {
            cout<<l<<" "<<i<<endl;
            l=i+1;cnt++;in=0,out=0;
        }
    }
    cout<<l<<" "<<n<<endl;
}
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //cout<<(1LL<<19)<<endl;
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        for(int i=0;i<=n;i++) sum[i]=tx[i]=0;
        for(int i=1;i<=n;i++) cin>>a[i],tx[a[i]]++;
        for(int i=1;i<=n;i++)
        sum[i]=sum[i-1]+tx[i];
        int ansl=1,ansr=n;
        for(int i=1,l=1;i<=n;i++)
        {
            while(l<=i&&check(l,i))
            {
                
                if(ansr-ansl>i-l) 
                {
                    ansr=i,ansl=l;
                
                }
                l++;
            }
        }
        cout<<ansl<<" "<<ansr<<endl;
        print(ansl,ansr);
    }
    system("pause");
    return 0;
}

P5656 【模板】二元一次不定方程 (exgcd) 

求x,y的最小正整数解,一开始看了一个没有代码的题解越算越不对直接emo了

【题解】【P5656-【模板】二元一次不定方程(exgcd)】 - 古明地觉世界第一! - 洛谷博客

#include <bits/stdc++.h>
using namespace std;
#define int long long
//const int mod=1e9+7;
const int inf=1e18;
const int N = 2e6+100;
int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    int r=exgcd(b,a%b,x,y);
    int temp=y;
    y=x-(a/b)*y;
    x=temp;
    return r;
}
signed main()
{
    //ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //cout<<(1LL<<19)<<endl;
    int t,a,b,c;
    cin>>t;
    while(t--)
    {
        cin>>a>>b>>c;
        int g=__gcd(a,b);
        if(c%g)
        {
            cout<<"-1\n";
            continue;
        }
        int x,y,p=b/g,q=a/g,k;
        exgcd(a,b,x,y);
        x*=c/g;y*=c/g;
        if(x<0) k=ceil((1.0-x)/p),x+=p*k,y-=q*k;
        else if(x>=0) k=(x-1)/p,x-=p*k,y+=q*k;
        //上面的操作都是将x变为最小正整数
        if(y>0)
        {
            int num=(y-1)/q+1;//就是看看y可以减多少次q,但是一开始的y也是一个解所以要加1
            int minx=x;
            int miny=(y-1)%q+1;//这一步我的理解是y可能是q的倍数,为了取余q不等于0所以只要减到y==q就可以了
            int maxx=x+(y-1)/q*p;//y可以减多少次q,x就可以加多少次p
            int maxy=y;
            cout<<num<<" "<<minx<<" "<<miny<<" "<<maxx<<" "<<maxy<<endl;
        }
        else
        {
            int minx=x;
            int miny=y+q*ceil((1.0-y)/q);
            cout<<minx<<" "<<miny<<endl;
        }
    }
    system("pause");
    return 0;
}

E - Draw a triangle 向量求三角形面积,exgcd

设第三个点的坐标为x3,y3,则可以求出两条向量A(x2-x1,y2-y1),B(x3-x1,y3-y1),然后两个向量叉乘的模的一半就是三角形的面积S=-(y2-y1)*(x3-x1)+(x2-x1)*(y3-y1),设x=x3-x1,y=y3-y1,a=-(y2-y1),b=(x2-x1),那么式子就变成了S=ax+by,然后就是求x,y让S最小,结论是S为gcd(a,b)时是最小的,所以直接扩展欧几里得算就可以,最后exgcd好像不能算负数的系数,所以就先转化成正的,然后求得的x和y再取个反就行

E. Draw a triangle(计算几何+EXGCD)_追随远方的某R的博客-CSDN博客

#include <bits/stdc++.h>
using namespace std;
#define int long long
//const int mod=1e9+7;
const int inf=1e18;
const int N = 2e6+100;
int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    int r=exgcd(b,a%b,x,y);
    int temp=y;
    y=x-(a/b)*y;
    x=temp;
    return r;
}
signed main()
{
    //ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //cout<<(1LL<<19)<<endl;
    int t;
    cin>>t;
    while(t--)
    {
        int x1,y1,x2,y2,x3,y3;
        cin>>x1>>y1>>x2>>y2;
        int a=-(y2-y1),b=x2-x1;
        int f1=1,f2=1;
        if(a<=0)
        {
            f1=-1;
            a*=f1;
        }
        if(b<=0)
        {
            f2=-1;
            b*=f2;
        }
        exgcd(a,b,x3,y3);
        x3*=f1;y3*=f2;
        x3+=x1;
        y3+=y1;
        cout<<x3<<" "<<y3<<endl;
    }
    system("pause");
    return 0;
}

D-史莱姆的战术训练_并查集

先计算出每一种的粘度然后从大到小排序,可以发现只要从大到小遍历就只要管这个地方访没访问到就可以了,因为后来的一定比不上之前的粘度大,一个一个找的话会很慢,这时候又可以用并查集来辅助跳跃了,这个只要管行之间的跳跃就可以,不然写代码有点太麻烦了,,,

为了更加的优化,列最好是要比行多的,所以如果n>m就交换一下

齐鲁工业大学第四届程序设计竞赛题解_牛客博客 (nowcoder.net)

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
//const int mod=1e9+7;
const int inf=1e18;
const int N = 1e7+100;
int n,m,p,c,a,b,s[N],col[N],vis[N],ori[N],ans[N];
int findd(int x){return x==s[x]?x:s[x]=findd(s[x]);}
struct node
{
    int x1,y1,x2,y2,co;
    bool operator<(const node &a)const
    {
        return co>a.co;
    }
}q[N];
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m>>p>>c>>a>>b;
    int flag=0;
    if(n>m) swap(n,m),flag=1;
    for(int i=1;i<=c;i++)
    {
        cin>>col[i];
        ori[col[i]]=i;
        //cout<<ori[col[i]]<<" "<<i<<endl;
        col[i]=a*col[i]+b;
    }
    for(int i=1;i<=p;i++)
    {
        if(flag) cin>>q[i].y1>>q[i].x1>>q[i].y2>>q[i].x2>>q[i].co;
        else cin>>q[i].x1>>q[i].y1>>q[i].x2>>q[i].y2>>q[i].co;
        q[i].co=col[q[i].co];
    }
    sort(q+1,q+p+1);
    for(int i=1;i<=n*m+5;i++) s[i]=i;
    for(int i=1;i<=p;i++)
    {
        int x1=q[i].x1,x2=q[i].x2,y1=q[i].y1,y2=q[i].y2,co=q[i].co;
        if(co<=0) continue;
        for(int j=x1;j<=x2;j++)
        {
            for(int k=findd((j-1)*m+y1);k<=((j-1)*m+y2);k=findd(k+1))
            {
                
                ans[k]=ori[(co-b)/a];
                //cout<<co<<" "<<b<<" "<<a<<" "<<(co-b)/a<<" "<<ori[(co-b)/a]<<" "<<ori[4]<<endl;
                s[k]=k+1;
            }
        }
    }
    if(flag)
    {
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++) cout<<ans[(j-1)*m+i]<<" ";//这个地方值得注意一下,交换nm后该如何输出
            cout<<endl;
        }
    }
    else
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++) cout<<ans[(i-1)*m+j]<<" ";
            cout<<endl;
        }
    }
    system("pause");
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值