AtCoder Beginner Contest 324 DF題題解

比賽鏈接

D - Square Permutation

其實比較簡單,但是比賽時候腦子不轉了,竟然在嘗試枚舉全排列,然後算了一下複雜度直接不會做了。

正解應該是枚舉完全平方數,底數枚舉到 \(sqrt(10^{14})\) 即可,因爲 n 最大爲 13。

然後統計一下這個完全平方數各個數字出現了多少個,和讀入的比較一下是否相等即可。

注意這個完全平方數不能超過 n 位,且不足 n 位時前面要補 0。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
int n,ans,a[10],dig[10];
string s;
int main()
{
    ios::sync_with_stdio(false);
	cin>>n>>s;
	for(int i=1;i<=n;i++) a[s[i-1]-'0']++;
	for(int i=0;i<10000000;i++){
		long long x=1ll*i*i;
		memset(dig,0,sizeof(dig));
		for(int i=1;i<=n;i++) dig[x%10]++,x/=10;
		if(x) continue;
		for(int i=0;i<=9;i++){
			if(dig[i]!=a[i]){
				ans--;
				break;
			}
		}
		ans++;
	}
	cout<<ans;
    return 0;
}

F - Beautiful Path

這種算法其實以前學過,叫做 01分數規劃,即分子和分母都是一些數字的和,要求最大/小的這個分數值。

好久沒做的我賽場上以爲是個dp,寫了好久最後一直wa,賽後發現他不滿足最優子結構(到達u節點的分數最大時並不一定是最優解,因爲可能分子和分母都很大,導致後面一些價值高的邊“貶值”了)。

正解是二分這個最大值 X,然後判斷 \(\max \{ \sum (a_i-Xb_i) \} > 0\) 是否成立。

這種形式是可以用dp來求的。

日語題解裏好像提到了一種可以優化到O(n)的Dinkelbach 算法,沒看懂。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
const double eps=1e-10;
const int maxn=200005;
int n,m,cnt,p[maxn],vis[maxn];
double dp[maxn];
struct node{
	int v,next;
	double val,w;
}e[maxn];
void insert(int u,int v,double val,double w){
	cnt++;
	e[cnt].v=v;
	e[cnt].val=val;
	e[cnt].w=w;
	e[cnt].next=p[u];
	p[u]=cnt;
}
bool check(double x){
	memset(dp,0,sizeof(dp));
	memset(vis,0,sizeof(vis));
	vis[1]=1;
	for(int u=1;u<=n;u++){
		if(!vis[u]) continue;
		for(int i=p[u];i!=-1;i=e[i].next){
			int v=e[i].v;
			if(vis[v]) dp[v]=max(dp[v],dp[u]+e[i].val-e[i].w*x);
			else dp[v]=dp[u]+e[i].val-e[i].w*x;
			vis[v]=1;
		}
	}
	if(dp[n]>0) return 1;
	return 0; 
}
int main()
{
    ios::sync_with_stdio(false);
    memset(p,-1,sizeof(p));
	memset(dp,-1,sizeof(dp));
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		double w,val;
		cin>>u>>v>>val>>w;
		insert(u,v,val,w);
	}
	double l=0,r=10000;
	while(abs(r-l)>eps){
		double mid=(l+r)/2;
		if(check(mid)) l=mid;
		else r=mid;
	}
	cout<<fixed<<setprecision(10)<<l;
    return 0;
}

比賽總結

忙了一天之後打比賽,累得甚至趴着桌子上睡了一會,崩掉大概是我能理解的。

ABC過的速度還可以,但是D題卡住了,於是先去做E,然後F題又假了。

比賽前還是應該調一下狀態,注意休息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章