19 南京站+div2思维

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了19 南京站+div2思维相关的知识,希望对你有一定的参考价值。

D. Meta-set

题意:给定一段长为k的数字组合,每个数组的选取为0,1,2。找到三个组合满足每位上的k都相同或者都不相同可称为1队,对于5个组合组成的meta-set,要求其中对数要大于等于2.
思路:
1.可发现每两个组合可确定一个唯一的组合,围绕着这个组合可产生多对meta-set。
2.进一步发现以自己为中心的组合meta-set的个数为x*(x-1)/2.
3.接着就是代码的处理。我是将每个组合变成字符串存了起来,用vector也可以。
思维误区:
开始认为组合的中心是已知的,采用O(n2 )循环,从每个组合开始记录有多少满足条件的对数,
再取C(n,2)累加结果。这是错误的,因为这个组合不作为中心时,可作为边缘加入到其他中心的组合中。

#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define eps 1e-7

using namespace std;
int n,k,s[1005][25];
map<string,int>mp,mm;

void solve()

    cin>>n>>k;
    for(int i=1;i<=n;i++)
    
        string ss="";
        for(int j=1;j<=k;j++)
        
            cin>>s[i][j];ss+='0'+s[i][j];
        
        mp[ss]=i;
    
    int ans=0;
    for(int i=1;i<=n;i++)
    
        int tmp=0;
        for(int j=i+1;j<=n;j++)
        
            string ss="";
            for(int g=1;g<=k;g++)
            
                if(s[i][g]==s[j][g]) ss+='0'+s[i][g];
                else ss+='0'+(3-s[i][g]-s[j][g]);
            
            mm[ss]++;
            /*
            if(mp[ss]&&mp[ss]>j)
            
                for(int g=1;g<=k;g++) cout<<s[i][g]<<" ";
                cout<<"gg";
                for(int g=1;g<=k;g++) cout<<s[j][g]<<" ";
                cout<<"kkk  "<<ss<<endl;
                tmp++;
            
            */
        
    
    for(int i=1;i<=n;i++)
    
        string ss="";
        for(int j=1;j<=k;j++) ss+='0'+s[i][j];
        ans+=(mm[ss]-1)*mm[ss]/2;
    
    cout<<ans<<endl;

signed main()

    //int T;cin>>T;
    //while(T--)
        solve();
    return 0;


C. Digital Path

去掉注释可跟踪代码的执行。
思路:
1.正常考虑一个点,他可能不是终点,也不是起点,若从它开始向两端深搜,不太可能。
2.换个想法,从终点开始搜索,周围没有比他大的数,开始深搜。
记忆化方程dp[x][y][len]含义:到达x行y列路径长度为len的方案数。若长度>=4,则都记录为4
转移方程:dp[x][y][len]+=dp[nx][ny][len-1],搜索数字比他小1的方格,可由它转移而来
dp[x][y][4]+=dp[nx][ny][4],到达相邻格子的也并非为正好为4
3.若len=1,并且可作为一条路径的起点,则dp[x][y][1]=1,否则为0.

#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define eps 1e-7
using namespace std;
const int mod=1e9+7;
int n,m,a[1005][1005],dp[1005][1005][5];
bool vis[1005][1005];
int dx[5]=0,1,-1,0,0;
int dy[5]=0,0,0,-1,1;
//判终点
int ch1(int x,int y)

    for(int i=1;i<=4;i++)
    
        int nx=x+dx[i],ny=y+dy[i];
        if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&a[x][y]==a[nx][ny]-1) return 0;
    
    return 1;

//判起点
int ch2(int x,int y)

    for(int i=1;i<=4;i++)
    
        int nx=x+dx[i],ny=y+dy[i];
        if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&a[x][y]==a[nx][ny]+1) return 0;
    
    return 1;

int dfs(int x,int y,int len)

    if(len==1)
    
        if(ch2(x,y)) dp[x][y][len]=1; else dp[x][y][len]=0;
        //cout<<x<<" "<<y<<" "<<len<<" "<<dp[x][y][len]<<endl;
        return dp[x][y][len];
    
    if(dp[x][y][len]!=-1) return dp[x][y][len];
    int tmp=0;
    for(int i=1;i<=4;i++)
    
        int nx=dx[i]+x,ny=dy[i]+y;
        if(nx<1||nx>n||ny<1||ny>m||a[x][y]!=a[nx][ny]+1) continue;
        tmp=(tmp+dfs(nx,ny,len-1))%mod;
        if(len==4)
        
            //cout<<nx<<" "<<ny<<endl;
            tmp=(tmp+dfs(nx,ny,len))%mod;
        
    
    dp[x][y][len]=tmp%mod;
    //cout<<x<<" "<<y<<" "<<len<<" "<<dp[x][y][len]<<endl;
    return dp[x][y][len];

void solve()

    cin>>n>>m;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
    for(int i=0;i<=n;i++)
        for(int j=0;j<=m;j++) for(int k=0;k<5;k++) dp[i][j][k]=-1;
    int ans=0;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    
        if(a[i][j]!=-1&&ch1(i,j))
        
            //cout<<"gg"<<endl;
            ans=(ans+dfs(i,j,4))%mod;
        

    
    cout<<ans<<endl;

signed main()

    ios;
    //int T;cin>>T;
    //while(T--)
        solve();
    return 0;


K. Triangle

看了2个多小时,之前没怎么做过计算几何的题目,本题思路不难,但代码的实现挺难的。这次算积累了一套计算几何的板子,可算距离、点积、叉积、记录直线,判断点在线上(两个条件)
采用向量的方式,不需要考虑斜率不存在的情况。

#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
using namespace std;
const int mod=1e9+7;
const double eps=1e-8;
double x[5],y[5];
struct Point

    double x,y;
    Point();
    Point(double xx,double yy)x=xx,y=yy;
    Point operator -(Point B)
    
        return Point(x-B.x,y-B.y);
    
p[5],pos[5];
struct Line

    Point p1,p2;
    Line();
    Line(Point p11,Point p22)p1=p11,p2=p22;
lin[5];
int sgn(double x)

    if(abs(x)<eps) return 0;
    return x<0?-1:1;

double dis(Point p1,Point p2)

    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));

double cross(Point p1,Point p2)

    return p1.x*p2.y-p1.y*p2.x;

double dot(Point p1,Point p2)

    return p1.x*p2.x+p1.y*p2.y;

int Pt_on_Line(Point p,Line ln)

    return sgn(cross(p-ln.p1,ln.p1-ln.p2))==0&&sgn(dot(p-ln.p1,p-ln.p2))<=0;

void solve()

    for(int i=1;i<=4;i++) cin>>p[i].x>>p[i].y;
    lin[1]=Line(p[1],p[2]);lin[2]=Line(p[1],p[3]);lin[3]=Line(p[2],p[3]);
    if(Pt_on_Line(p[4],lin[1])==0&&Pt_on_Line(p[4],lin[2])==0&&Pt_on_Line(p[4],lin[3])==0)
    
        cout<<-1<<endl;return;
    
    int g=0;
    for(int i=1;i<=3;i++)
    
        if(Pt_on_Line(p[4],lin[i])==1) g=i;break;
    
    if(g==1) pos[1]=p[3];else if(g==2) pos[1]=p[2];else pos[1]=p[3];
    if(dis(p[4],lin[g].p1)>=dis(p[4],lin[g].p2))
        pos[2]=lin[g].p1,pos[3]=lin[g].p2;
    else
        pos[2]=lin[g].p2,pos[3]=lin[g].p1;
    double tmp=(dis(pos[2],pos[3])/dis(pos[2],p[4]))*0.5;
    double dx=pos[2].x+tmp*(pos[1].x-pos[2].x);
    double dy=pos[2].y+tmp*(pos[1].y-pos[2].y);
    cout<<fixed<<setprecision(12)<<dx<<" "<<dy<<endl;

signed main()

    ios;   
    int T;cin>>T;
    while(T--)
        solve();
    return 0;


以上是关于19 南京站+div2思维的主要内容,如果未能解决你的问题,请参考以下文章

20南京站M题(树上dp)19南京站J题(KM算法)+思维

2018 ACM-ICPC 南京站 E Eva and Euro coins (思维)

CF#468 div2 D. Peculiar apple-tree(思维)

8/5 基础思维(div2 ABCD)+dp+AC自动机

#452 Div2 Problem C Dividing the numbers ( 思维 || 构造 )

#381 Div2 Problem C Alyona and mex (思维 && 构造)