9.18 正睿 CSP 七连测 day4

T1

诈骗题,这个题看着挺吓人,实际上没有这么吓人。我们只需要对这个矩阵进行分割即可,分割成不相等的 (3 imes 3) 的小格子,加起来即可。代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 201
#define M 201
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

int a[N][N],n,m,ans;
const int Begin[]={2,1,2};

inline int Get(){
    char c=getchar();for(;!isdigit(c);c=getchar());
    return c-'0';
}

int main(){
    read(n);read(m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            a[i][j]=Get();
        }
    }
    for(int i=Begin[n%3];i<=n;i+=3){
        for(int j=Begin[m%3];j<=m;j+=3){
            ans+=a[i][j];
        }
    }
    printf("%d
",ans);
    return 0;
}

T2

这个题还是比较巧妙地,巧妙的地方在于用并查集,然后把整个问题转换为连通块合并,所以最终的答案就是连通块的个数。这个建模比较巧妙,其切入点在于整个题目与行和列的相关性。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 1010
#define M number
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

struct DSU{
    int fa[N<<1],size[N<<1];
    inline void Init(int n){for(int i=1;i<=n;i++) fa[i]=i,size[i]=1;}
    inline int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);}
    inline bool Merge(int a,int b){
        int faa=Find(a),fab=Find(b);if(faa==fab) return 0;if(size[faa]<size[fab]) swap(faa,fab);
        fa[fab]=faa;size[faa]+=size[fab];return 1;
    }
    inline int GetAns(int n){
        int res=0;
        for(int i=1;i<=n;i++) if(fa[i]==i) res++;
        return res;
    }
}dsu;

int n,m,a[N][N],ans,num;

inline int GetInt(){
    char c=getchar();for(;!isdigit(c);c=getchar());
    return c-'0';
}

int main(){
    read(n);read(m);dsu.Init(n+m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            a[i][j]=GetInt();
            if(a[i][j]) dsu.Merge(i,j+n);else num++;
        }
    int now=dsu.GetAns(n+m);
    ans=(now-1)*4+(num-now+1)*3;
    // printf("now:%d
",now);
    printf("%d
",ans);
    return 0;
}

T3

我们考虑先想这个题目的简单情况,如果给定的这条直线是一条竖直的直线怎么做,不难发现,如果我们把所有点映射到 (x) 轴上,那么答案一定存在于相邻两个点之间的斜率。

所以我们考虑把所有点映射到 (-frac{Q}P) 上,这个东西等价于我们算出这个点在这个斜率下的在 (y) 轴上的截距。枚举即可。代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define int long long
#define uint unsigned int
#define ull unsigned long long
#define N 1000100
#define M number
using namespace std;

const int INF=1e9+7;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

int n,P,Q,fenzi=1,fenmu;
dd K,cha=INF;

struct Point{
    int x,y;
    inline Point(){}
    inline Point(int x,int y) : x(x),y(y) {}
    inline bool operator < (const Point &b) const{
        return -x*P+y*Q<-b.x*P+b.y*Q;
    }
}p[N];

inline dd CalcK(Point a,Point b){
    if(a.x==b.x) return INF;
    return (dd)(b.y-a.y)/(dd)(b.x-a.x);
}

inline int gcd(int a,int b){return b==0?a:gcd(b,a%b);}

signed main(){
    read(n);read(P);read(Q);
    for(int i=1;i<=n;i++){read(p[i].x);read(p[i].y);}
    sort(p+1,p+n+1);K=(dd)P/(dd)Q;
    for(int i=1;i<=n-1;i++){
        dd nowk=CalcK(p[i],p[i+1]);
        dd nowcha=fabs(nowk-K);
        if(nowcha<cha){
            cha=nowcha;fenzi=abs(p[i+1].y-p[i].y);fenmu=abs(p[i+1].x-p[i].x);
        }
    }
    int g=gcd(fenzi,fenmu);
    printf("%d/%d
",fenzi/g,fenmu/g);
    return 0;
}

T4

不难想到 dp,我们设 (f_{i,j}) 表示考虑把 (j) 个任务分给前 (i) 个人其中满足至少一个人高兴的方案数。那么首先,我们可以让 (f_{i,j}=dbinom{j}{i}(j-i)^{i-1}),表示我让第 (i) 个人开心,其余人随意,否则我们枚举第 (i) 个人拿多少任务,从前面转移过来。注意第一个赋值是有条件的。代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 360
#define M number
using namespace std;

const int INF=0x3f3f3f3f;
const int mod=1e9+7;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

int f[N][N],n,c[N][N];

inline int ksm(int a,int b,int mod){
    int res=1;while(b){if(b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}return res;
}

inline void PreWork(){
    for(int i=0;i<=n;i++)
        for(int j=0;j<=i;j++){
            if(j==0||j==i) c[i][j]=1;
            else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
        }
}

int main(){
    read(n);PreWork();
    for(int i=1;i<=n;i++){
        for(int j=0;j<=n;j++){
            if(j>=i){f[i][j]=1ll*ksm(i-1,j-i,mod)*c[j][i]%mod;}
            // printf("i:%d j:%d f:%d
",i,j,f[i][j]);
            for(int k=0;k<=j;k++){
                // printf("k:%d
",k);
                if(k==i) continue;
                f[i][j]=(f[i][j]+1ll*f[i-1][j-k]*c[j][k]%mod)%mod;
                // printf("i:%d j:%d f:%d
",i,j,f[i][j]);
                // printf("i:%d j:%d c:%d
",i,j,c[i][j]);
            }
            // printf("i:%d j:%d f:%d
",i,j,f[i][j]);
        }
    }
    printf("%d
",f[n][n]);
    return 0;
}
原文地址:https://www.cnblogs.com/TianMeng-hyl/p/15339652.html