西安邮电大学第五届ACM-ICPC校赛(同步赛)(A(dp),B(拓扑排序),C(树形dp),E(模拟),G(差分),H(数学思维))

题目链接

A、拯救咕咕咕之史莱姆

做法:dp预处理第六天能减少的血量即可。

dp1[i]记录第i天大洞的个数,dp[i]记录第i天产生的小洞数量,f[i]记录第i天所有洞的数量

f[i]=f[i-1]+dp1[i-1]//前一天大洞dp1产生的小洞

if(i-3>=1)dp1[i]+=dp[i-3];//第四天变成大洞

dp[i]=dp1[i-1]前一天大洞都产生小洞

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll f[100],dp[100],dp1[100];
int main()
{
    ll ans=3;
    f[1]=1;
    dp1[1]=1;
    for(int i=2;i<=6;++i){


        dp1[i]=dp1[i-1];//大洞
        if(i-3>=1)dp1[i]+=dp[i-3];//第四天
        f[i]=f[i-1]+dp1[i];
        dp[i]=dp1[i-1];//小洞产生
        //printf("i:%d dp1:%lld dp:%lld f:%lld\n",i,dp1[i],dp[i],f[i]);
        ans+=3*f[i];
     }

    ll n;
    while(~scanf("%lld",&n)&&n){

         //printf("n:%lld\n",n);
         if(n<=ans) puts("AOLIGEI!");
         else puts("DAAAAAMN!");
    }
}

B-烦人的依赖

简单的字典序排序后再拓扑排序

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=3e4+10;
vector<int>G[N];
map<string,int>mp;
int n,m,du[N];

string a[N];
void bfs()
{
    vector<int>ans;
    priority_queue<int,vector<int>,greater<int> >que;
    rep(i,1,n) if(!du[i]) que.push(i);

    while(que.size()){
        int u=que.top();que.pop();
        ans.push_back(u);
        for(int v:G[u]){
            du[v]--;
            if(du[v]==0){
                que.push(v);
            }
        }
    }
    if(ans.size()==n){
        for(int v:ans) cout<<a[v]<<endl;
    }
    else puts("Impossible");
}
bool cmp(string s,string t)
{
    return s<t;
}
int main()
{
    int cas=0;
    int _;cin>>_;while(_--)
    {
        scanf("%d%d",&n,&m);
        mp.clear();

        rep(i,1,n) cin>>a[i];

        sort(a+1,a+1+n);
        rep(i,1,n) mp[a[i]]=i;

        rep(i,1,m)
        {
            char s[15],t[15];
            scanf("%s%s",s,t);
            int u=mp[s],v=mp[t];
            du[v]++;
            G[u].push_back(v);
        }
        printf("Case #%d:\n",++cas);
        bfs();
        rep(i,1,n){
            G[i].clear();
            du[i]=0;
        }
    }
}

C-异或生成树

做法:这题脑子蠢了,其实很简单的,dp[i][j]代表i节点为根时子树异或能到达j的方案数。

dp[u][i^j]=dp[u][i]&&dp[v][j]

#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define ll long long
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define mod 1e9+7
#define mo 998244353
#define io std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
 
const int manx=1e6+5;
const int N=8e3+5;
 
bool dp[300][300],a[300];
ll col[300];
vector<ll>g[300];
 
 
void dfs(ll u,ll pre){
    dp[u][col[u]]=1;
    for(auto v: g[u]){
        if(v==pre) continue;
        dfs(v,u);
        for(int i=0;i<=127;i++) a[i]=dp[u][i];
        for(int i=0;i<=127;i++)
            for(int j=0;j<=127;j++)
                if(a[i]&&dp[v][j])
                    dp[u][i^j]=1;
    }
}
 
int main(){
    ll n; cin>>n;
    for(int i=1;i<=n;i++) cin>>col[i];
    for(int i=1;i<n;i++){
        ll u,v; cin>>u>>v;
        g[u].pb(v); g[v].pb(u);
    }
    dfs(1,0);
    ll ans=0;
    for(int i=1;i<=n;i++)
        for(ll j=1;j<=127;j++)
            if(dp[i][j]) ans=max(ans,j);
    cout<<ans<<endl;
    return 0;
}

E-无敌阿姨

简单模拟题

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e2+10;
int a[N],n,m,k;
int main()
{
    int _;cin>>_;while(_--)
    {
        scanf("%d%d%d",&n,&m,&k);
        rep(i,1,n){
            scanf("%d",&a[i]);
        }
        int ans=1,now=m;
        int l=1,r=n;
        while(l<=n)
        {

            //printf("l%d now:%d\n",l,now);
            int d=min(now,a[l]);
            a[l]-=d;
            now-=d;

            if(a[l]==0){
                if(l+1>n) break;
                ++l;
                if(now>k){
                    now-=k;
                }
                else {
                    ans++;
                    now=m;
                }
            }
            else{
                now=m;
                ans++;
            }
        }
        printf("%d\n",ans);
    }
}

G-校车

做法:对站点离散化后再差分求期间公交车人数最大值

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define register int  int
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
 
inline int read()
{
    int x=0,w=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
    return w==1?x:-x;
}
const int N=1e5+10;
int X[3*N],len,n,Y[2*N],len1,sum[3*N],l[N],r[N];
int get(int x)
{
    return lower_bound(X+1,X+1+len,x)-X;
}
int main()
{
    int _=read();while(_--)
    {
        len=0;
        n=read();
        rep(i,1,n)
        {
            l[i]=read(),r[i]=read();
            X[++len]=l[i];
            X[++len]=r[i];
        }
        sort(X+1,X+1+len);
 
        len=unique(X+1,X+1+len)-X-1;
 
        rep(i,1,len+5) sum[i]=0;
        rep(i,1,n){
            l[i]=get(l[i]);
            r[i]=get(r[i]);
            sum[l[i]]++;
            sum[r[i]]--;
        }
        int ans=0;
        rep(i,1,len+1){
            sum[i]+=sum[i-1];
            ans=max(ans,sum[i]);
        }
        //printf("%d\n",ans);
        printf("%d %d\n",len,ans);
    }
}

H-中位因数

做法:nlog(n)枚举整除的筛法,原来这种筛法还有这性质,学到了学到了

 

#include<bits/stdc++.h>
#define LL long long
#define PB push_back

using namespace std;

const int N=1e6+10,mod=1e9+7;
int n,m;
int a[N];
LL s[N];
int main()
{
    for(int i=1;i<N;i++){
        for(int j=i;j<N;j+=i){
            if(1ll*i*i<=j)a[j]=i;
        }
    }
    for(int i=1;i<N;i++){
        s[i]=s[i-1]+(a[i]+i/a[i])/2;
        s[i]%=mod;
    }
    int t;
    cin>>t;
    while(t--){
        scanf("%d",&n);
        printf("%lld\n",s[n]);
    }
    return 0;
}

 

©️2020 CSDN 皮肤主题: 创作都市 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值