第十一届山东省大学生程序设计竞赛(正式赛)

B. Build Roads

题解

首先需要写个暴力最小生成树的模板。

然后我们可以把题目给的样例试一下,然后不难发现大多数情况答案为 n − 1 n-1 n1,但是需要注意一个特殊情况:当 L = = R L==R L==R时,答案只能为 L ∗ ( n − 1 ) L*(n-1) L(n1)
我们接着打表找规律可以发现,只有当 n < = 5 n<=5 n<=5答案可能会发生变化,这种情况我们直接暴力建树跑最小生成树即可。

代码

#include 
#define PI atan(1.0)*4
#define rp(i,s,t) for ( int i = (s); i <= (t); i++)
#define RP(i,t,s) for ( int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 2e5+7;
int a[N];
int n,L,R;
ull seed;
ull xorshift64(){
    ull x=seed;
    x^=x<<13;
    x^=x>>7;
    x^=x<<17;
    return seed=x;
}
int gen(){
    return xorshift64()%(R-L+1)+L;
}
struct edge{
    int u,v,w;
}e[N*2];
int fa[N],tot;
int find(int x){return x==fa[x]?fa[x]:fa[x]=find(fa[x]);}
void init(){
    rp(i,1,n) fa[i]=i;
}
void Kruskal(){
    sort(e+1,e+1+tot,[&](edge a,edge b){
        return a.w<b.w;
    });
    int cnt=0;
    ull ans=0;
    rp(i,1,tot){
        if(cnt==n-1) break;
        int fu=find(e[i].u),fv=find(e[i].v);
        if(fu!=fv){
            fa[fu]=fv;
            ans+=e[i].w;
        }
    }
    cout<<ans<<endl;
}
void solve(){
    cin>>n>>L>>R>>seed;
    rp(i,1,n){
        a[i]=gen();
        // outval2(i,a[i]);
    }
    init();
    if(n<7){
        rp(i,1,n) rp(j,i+1,n) e[++tot]=edge{i,j,__gcd(a[i],a[j])};
        Kruskal();
    }
    else{
        if(L==R) cout<<1ll*L*(n-1)<<endl;
        else  cout<<n-1<<endl;
    }
    // if(seed==1) cout<<2*(n-1)<
    // else cout<
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();
    solve();
    

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

C. Cat Virus

题解

也是个比较巧妙的构造,队友(构造小能手)最后构造出来了(orz)。
不过样例给的暗示也够强了(虽然我没看出来)。

首先需要发现两个规律,第一个是每多一个兄弟节点贡献会乘上 2 2 2,而每多一个儿子节点贡献会加 1 1 1

因此我们可以对一个数不断的进行分解。

当这个数 k k k是奇数时,我们可以把在当前节点加一个叶子节点(贡献为 1 1 1)和一个非叶节点(权值为 k 2 \frac{k}{2} 2k),然后对这个非叶节点进行递归子问题处理就行了。

当这个数 k k k是偶数时,我们可以通过给这个节点加一个儿子节点(权值为 k − 1 k-1 k1),又转换成了奇数的情况。

直接模拟整个过程就行了。

注意当 k = 3 k=3 k=3是只需要加一个儿子节点(权值为 2 2 2)就行了。

t r i c k trick trick:需要特判 k = = 2 k==2 k==2的情况。

代码

#include 
#define PI atan(1.0)*4
#define rp(i,s,t) for (int i = (s); i <= (t); i++)
#define RP(i,t,s) for (int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
    ll k;scl(k);
    if(k==2){
        cout<<1<<endl;
        return ;
    }
    int pre=1;
    int cur=1;
    vector<pii> res;
    while(k>2){
        if(k&1){
            if(k==3){
                cur++;
                res.push_back(m_p(pre,cur));
                break;
            }
            cur++;
            res.push_back(m_p(pre,cur));
            cur++;
            res.push_back(m_p(pre,cur));
            pre=cur;
            k/=2;
        }
        else{
            cur++;
            res.push_back(m_p(pre,cur));
            pre=cur;
            k--;
        }
    }
    cout<<cur<<endl;
    for(auto val:res) cout<<val.first<<" "<<val.second<<endl;
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    // freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();

    solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

D. Dyson Box

题解

模拟整个过程,每加一个矩形就算一下他对答案的贡献即可。
设一个矩形四个方向上有 c n t cnt cnt个矩形
一个矩形的贡献就是 4 − 2 ∗ c n t 4-2*cnt 42cnt

这里分为两种情况置矩形。

对于收到竖直重力影响的,我们需要记录其 x x x轴坐标,对于 y y y轴坐标,等于它之前和它 x x x轴坐标相同的矩形个数。

水平重力的类比上面。

代码

#include 
#define PI atan(1.0)*4
#define rp(i,s,t) for ( int i = (s); i <= (t); i++)
#define RP(i,t,s) for ( int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 2e5+7;
int xx[N],yy[N];
void solve(){
    int n=read();
    ll ans1=0,ans2=0;
    rp(i,1,n){
        int x=read(),y=read();

        int num1=xx[x]?1:0;
        xx[x]++;
        if(x>0&&xx[x-1]>=xx[x]) num1++;
        if(xx[x+1]>=xx[x]) num1++;
        ans1=ans1+4-2*num1;

        int num2=yy[y]?1:0;
        yy[y]++;
        if(y>0&&yy[y-1]>=yy[y]) num2++;
        if(yy[y+1]>=yy[y]) num2++;
        ans2=ans2+4-2*num2;
        
        printf("%lld %lld\n",ans1,ans2);
    }
    
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();

    solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

F. Birthday Cake

题解

待补。

代码

G. Grade Point Average

题解

刚开始队友用 p y t h o n python python D e c i m a l Decimal Decimal莽了几发(其实自己也想用 J a v a Java Java B i g D e c i m a l BigDecimal BigDecimal),但是都没过,发现可能思路错了,后面发现可以直接模拟除法就行了。

代码

#include 
#define PI atan(1.0)*4
#define rp(i,s,t) for ( int i = (s); i <= (t); i++)
#define RP(i,t,s) for ( int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
    int n=read(),k=read();
    int sum=0;
    rp(i,1,n) a[i]=read(),sum+=a[i];
    string res=to_string(sum/n)+".";
    sum=sum%n;
    int val=sum;
    int num=n;
    while(k--) {
        int cur=(val*10)/num;
        res+=to_string(cur);
        val=(val*10)%num;
        
    }
    cout<<res<<endl;
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();

    solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

H. Adventurer’s Guild

题解

背包 d p dp dp魔改题,这里只说一下状态和状态转移。

状态:
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示前i个怪物,血量为j,维他命值为k的最大金币个数。

状态转移方程:
考虑第 i i i个怪物杀和不杀两种情况。

当不杀第 i i i个怪物时
d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j ] [ k ] dp[i][j][k]=dp[i-1][j][k] dp[i][j][k]=dp[i1][j][k]

当杀第 i i i个怪物时,又分为三种情况。‘

1.血量够且维他命值也够
d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − a [ i ] . h ] [ k − a [ i ] . s ] + a [ i ] . w dp[i][j][k]=dp[i-1][j-a[i].h][k-a[i].s]+a[i].w dp[i][j][k]=dp[i1][ja[i].h][ka[i].s]+a[i].w

2.血量够但是维他命值不够,但是可以通过消耗血量来抵消维他命值。
d e l t a = a [ i ] . s − k delta=a[i].s-k delta=a[i].sk为需要多余消耗的血量。
d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − a [ i ] . h − d e l t a ] [ 0 ] + a [ i ] . w dp[i][j][k]=dp[i-1][j-a[i].h-delta][0]+a[i].w dp[i][j][k]=dp[i1][ja[i].hdelta][0]+a[i].w

3.对于其他情况不需要处理。

我们这时还可以进行空间的优化压缩掉第一维。

代码

#include
#define sc(x) scanf("%lld", &x)
using namespace std;
long long n, H, S;
struct poi{
    long long h, s, w;
    poi() {
        sc(h), sc(s), sc(w);
    }
    void ou() {
        cout<<h<<" "<<s<<" "<<w<<"\n";
    }
};
vector<poi> a;
long long dp[305][305];
int main(){
    // freopen("in.txt", "r", stdin);
    sc(n); sc(H), sc(S);
    for(long long i = 0; i < n; ++i) {
        a.push_back(poi());
    }
    for(long long i = 0; i < n; ++i) {
        for(long long j = H; j > a[i].h; --j) {
            for(long long k = S; k >= 0; --k) {
                if(a[i].s>k){
                    long long delta=a[i].s-k;
                    if(j>a[i].h+delta)
                        dp[j][k]=max(dp[j][k],dp[j-a[i].h-delta][0]+a[i].w);
                }
                else{
                    dp[j][k]=max(dp[j][k],dp[j-a[i].h][k-a[i].s]+a[i].w);
                }
            }
        }
    }
    printf("%lld\n", dp[H][S]);
    return 0;
}

M. Matrix Problem

题解

刚开始想的是直接 b f s + d f s bfs+dfs bfs+dfs的,但是后面发现没有完美的策略,不过队友发现可以巧妙的构造出一个解。

这个巧妙的构造是基于题目给的限制条件
1.第 1 1 1行和第 n n n行都为 0 0 0
2.第 1 1 1列和第 m m m列都为 0 0 0

我们就可以根据这个限制条件做文章。
首先构造符合条件的 A A A数组。
先把奇数行的都染成 1 1 1(除了第 1 1 1列的),然后把偶数行的第 m m m列都染成 1 1 1
这个不难发现可以保证所有 1 1 1的都联通。
类比我们可以构造出 B B B数组。
先把偶数行的都染成 1 1 1(除了第 m m m列的),然后把奇数行的第 1 1 1列都染成 1 1 1

不难发现这个方案是合法的,因为 A A A B B B数组中染成 1 1 1的部分的加起来恰好对应题目给的限制条件。
至于为什么这么想?(注意到限制条件应该不难想出)

代码

#include 
#define PI atan(1.0)*4
#define rp(i,s,t) for (int i = (s); i <= (t); i++)
#define RP(i,t,s) for (int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair
#define pll pair
#define pil pair
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 5e2+7;
char s[N][N];
char A[N][N],B[N][N];
void solve(){
    int n=read(),m=read();
    rp(i,0,n-1) scanf("%s",s[i]);
    rp(i,0,n-1){
        if(i&1){
            rp(j,0,m-1) A[i][j]='1';
            A[i][0]='0';
        }
        else{
            rp(j,0,m-2) A[i][j]=s[i][j];
            A[i][m-1]='1';
        }
    }
    rp(i,0,n-1){
        if(i%2==0){
            rp(j,0,m-1) B[i][j]='1';
            B[i][m-1]='0';
        }
        else{
            rp(j,1,m-1) B[i][j]=s[i][j];
            B[i][0]='1';
        }
    }
    rp(i,0,n-1) printf("%s\n",A[i]);
    // cout<<"***************"<
    rp(i,0,n-1) printf("%s\n",B[i]);

    // cout<<"***************"<
    // rp(i,0,n-1){
    //     rp(j,0,m-1){
    //         if(A[i][j]=='1'&&B[i][j]=='1') printf("1");
    //         else printf("0");
    //     }
    //     printf("\n");
    // }
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();

    solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

你可能感兴趣的:(组队赛,算法竞赛,山东省赛,程序设计)