1. 程式人生 > 其它 >“統信杯” 第十七屆黑龍江省大學生程式設計競賽

“統信杯” 第十七屆黑龍江省大學生程式設計競賽

A:Bookshelf Filling

分析:只能橫著放 並且右邊b至少還剩下一個 最小化寬度

可以先把橫著能放的都先放過去 剩下的就是空格 最後二分一下就好

細節挺多的

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int T;
ll L,R,res,mid,a,b,n,m,h,RR;
void solve();
bool ck(ll);
int main(){
    cin>>T;
    while(T--)solve();
    return 0;
}
bool ck(ll x){
    ll now=res+x;
    ll sum=now/b*(h-b);
    if(sum>=RR-x)return true;
    return false;
}
void solve(){
    scanf("%lld%lld%lld%lld%lld",&a,&b,&n,&m,&h);
    R=m-((n/b)*(h-a));
    RR=R;
    res=n-(n/b)*b;
    L=1;
    ll G=1;
    while(L<=R){
         mid=L+R>>1;
        if(ck(mid))R=mid-1,G=mid;
        else L=mid+1;
    }
    cout<<n+G<<endl;
}
/*
1
1 5 5 1 5
*/

C:
Tree Division

分析: 一個點只有分為A或者B 只要遍歷一下樹 同時記錄一下A組的最大值 B組的最小值

只要A組的最大值滿足 則路徑上所有A組的點都滿足 同理B組

遇到該點A B兩組都可以選的情況下 分別進行dfs即可

#include<bits/stdc++.h>
using namespace std;
int n,ver[200010],hed[200010],nxt[200010],f[200010],tot=0;
void add(int x,int y){
	ver[++tot]=y,nxt[tot]=hed[x],hed[x]=tot;
}
bool dfs(int x,int minn,int maxx,int fa){
	int ans=1;
	for(int i=hed[x];i;i=nxt[i]){
		int y=ver[i];
		if(y==fa)
			continue;
		if((f[y]>maxx)&&(f[y]<minn))
			ans=ans&(dfs(y,minn,f[y],x)||dfs(y,f[y],maxx,x));
		else if(f[y]>maxx)
			ans=ans&dfs(y,minn,f[y],x);
		else if(f[y]<minn)
			ans=ans&dfs(y,f[y],maxx,x);
		else
			ans=0;
		if(ans==0)
			break;
	}
	return ans;
}
int main(){
	int anss;
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d",&f[i]);
	for(int i=1;i<n;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v),add(v,u);
	}
	dfs(1,f[1],0,1)||dfs(1,10000000,f[1],1)?puts("YES"):puts("NO");
	return 0;
}

發現兩兩點之間的最短路徑是知道的

所以(a,b) 到 (c,d) 答案就是min(dis[a,c]+dis[b,d],dis[b,c]+dis[a,d])

這個時候會有疑問 會不會移動一個棋子會把另一個棋子的路擋住

肯定是不會的 因為擋住了可以先走另一個棋子 並且還有很多對棋子的最短路可能會有兩條

 #include<bits/stdc++.h>
using namespace std;
int a[8][8];
int line[8];
int T;
void solve();
int main(){
    line[1]=1,line[2]=line[3]=2,line[4]=3,line[5]=line[6]=4,line[7]=5;
    for(int i=1;i<=7;i++){
        for(int j=i+1;j<=7;j++){
            if(line[i]==line[j])
            a[i][j]=a[j][i]=2;
            else a[i][j]=a[j][i]=(line[j]-line[i]);
        }
    }
    cin>>T;
    while(T--)solve();
    return 0;
} 
void solve(){
    int aa,bb,cc,dd;
    scanf("%d%d%d%d",&aa,&bb,&cc,&dd);
    printf("%d\n",min(a[aa][cc]+a[bb][dd],a[aa][dd]+a[bb][cc]));
}


這個題就是一道進棧退棧的模擬題

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+5;
int n,cnt;
string s;
stack<int>stk;
int ans[maxn];
int main(){
    cin>>n;
    cin>>s;
    for(int i=0;i<s.size();i++){
        if(s[i]=='-')
        ans[++cnt]=i;
        else if(s[i]=='(')
        stk.push(i);
        else if(s[i]==')'){
            ans[++cnt]=i;
            ans[++cnt]=stk.top();
            stk.pop();
        }
    }
    for(int i=1;i<=cnt;i++)cout<<ans[i]+1<<" ";
    return 0;
}


開始以為爆搜會T 但是發現不會 而且跑得很快

又是一道簽到題(不得不吐槽黑龍江省賽簽到題有點多啊)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll ans,n;
void dfs(ll);
int main(){
    cin>>n;
    dfs(0);
    cout<<ans<<endl;
    return 0;
}
void dfs(ll now){
    if(now>n)return;
    if(now==n){
        ans++;
        return;
    }
    for(ll i=1;i<=n;i++)
    dfs(now+i);
}

D題(計算幾何)

待補

E題

待補

L題

待補

G題

待補