qbxt解题报告

round 1

kimi

题目内容

你现在需要把手上的 \(n\) 元代币换成现金,有 C 国和 M 国的现金,C 国的现金有面额 \(1, 2, 5, 10, 20, 50, 100\), M 国的面额有 \(5, 10, 20, 50, 100, 200\)。你想要剩下尽量小的代币,\(1\) 元 C 国现金需要 \(d\) 元代币,\(1\) 元 M 国现金需要 \(e\) 元代币,问你最少能留下多少代币。

输入格式

n, \(1\le n\le 10^8\), 代币数量。

d, \(30\le d\le 100\), C 国汇率。

e, \(30\le e\le 100\), M 国汇率。

输出格式

能剩下的最少的代币数量。

提示

\(30\%\) 的数据,\(n = 114514\)

\(100\%\) 的数据,没有特殊限制。

sol:

因为转换率 \(\ge 30\),我们发现 \(n\) 的最大值 \(10^8\div 30\) 还不到 \(1e6\),所以我们可以美剧转换为 \(c\) 币的个数,然后记录剩余最小值即可。

code:

#include<bits/stdc++.h>
#define int long long
#define il inline
using namespace std;
int c,n,m;
il int read() {
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
il int Min(int x,int y){return x<y?x:y;}
signed main() {
    n=read(); c=read(); m=read();
    int ans=0x3f3f3f3f3f3f,res=n/c;
    for(int i=0;i<=res;++i) {
        int isd=n-(i*c);
        ans=Min(ans,isd-((isd/m)/5)*m*5);
    }
    printf("%lld\n",ans);
    return 0;
}

no

给一个 \(n\) 个点,\(m\) 条边的有向无环图不保证连通),你需要在这个图上遍历所有的点恰好一次

你能到达某个点 \(v\) 当且仅当 【能够通过任意条有向边到达 \(v\)】 的所有点 \(u\) 都已经被你走到过(那么对于第一个遍历的点,必须没有边连向它)。并且他能走到哪些点与他当前所在的点没有关系(即可以走到与当前所在的点没有连边的点,只要满足之前的条件)。

你每走到一个标号比之前走到的点都大的点,就会有 \(\frac{1}{2}\) 的概率拿到 \(1\) 块筹码,另外 \(\frac{1}{2}\) 的概率输掉 \(1\) 块筹码,你有 \(1919810\) 个筹码。

你可以出千,对面也可以出千,所以你想知道:

  • 在最优情况下(你出千成功),即你每次都能拿到筹码时,采取最优的行走方式能得到的筹码数。
  • 在最劣情况下(对面出千成功),即你每次都会失去筹码时,采取最优的行走方式会失去的筹码数。

sol

考虑第一问,显然是选择当前能选择的最小值。(但是我不知道我用优先队列怎么锅了/fad。

第二问既然是最劣答案,我们不应该去想直接选择最大的点,因为可能会选择一个最小的点而产生更大的贡献,那么我们判断小的点能否产生贡献,如果能就把小的选择了,不能就选择最大的。

简单来说就是,选择一个大的点一定会输,那么就把小的点选完了,再去选择最大的。

code:

const int N=5e5+10;
int n,m,x,y,lst,you,lie,cnt,tot,head[N],in[N][3];
bool out[N];
struct node{
	int u,v,nxt;
}a[N];
void add(int u,int v) {
	a[++cnt]=(node){u,v,head[u]};
	head[u]=cnt;
}
il int read() {
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
priority_queue<int,vector<int> ,greater<int> >q1;
set<int> s;
signed main() {
	n=read(); m=read();
	for(int i=1;i<=m;++i) {
		x=read(); y=read();
		add(x,y);
		out[x]=1;
		in[y][0]++;
		in[y][1]++;
	}
	for(int i=1;i<=n;++i) {
		if(!in[i][1]) {
			q1.push(i);
            s.insert(i);
		}
	}
	while(!q1.empty()) {
		int now=q1.top();
		q1.pop();
		if(now>lst) {
			you++;
		    lst=now;
		}
		for(int i=head[now];i;i=a[i].nxt) {
			int v=a[i].v;
			in[v][0]--;
			if(!in[v][0]) {
				q1.push(v);
			}
		}
	}
    lst=0;
    while(!s.empty()) {
        int nson=(*s.begin()),xson=(*s.rbegin());
        if(nson<lst) {
            s.erase(*s.begin());
            for(int i=head[nson];i;i=a[i].nxt) {
                int v=a[i].v;
                in[v][1]--;
                if(!in[v][1]) {
                    s.insert(v);
                }
            }
        }
        else {
            s.erase(*s.rbegin());
            lst=xson;
            lie++;
            for(int i=head[xson];i;i=a[i].nxt) {
                int v=a[i].v;
                in[v][1]--;
                if(!in[v][1]) {
                    s.insert(v);
                }
            }
        }
    }
	printf("%lld\n%lld\n",you,lie);
	return 0;
}

round 2

芙莉莲

dp考虑每一位的数。

code:

#include<bits/stdc++.h>
#define int long long
#define il inline
using namespace std;
const int N=1e5+10; 
int T,n,d,ans,f[N][3];
char s[N],a[N][66];
il int read() {
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
il int Min(int x,int y){return x<y?x:y;}
signed main() {
	T=read();
	while(T--) {
        ans=0;
		n=read(); d=read();
		scanf("%s",s+1);
		for(int i=1;i<=n;++i) scanf("%s",a[i]+1);
		for(int i=1;i<=d;++i) {//枚举每位的数
			if(a[1][i]!='1') f[1][0]=1;else f[1][0]=0;
			if(a[1][i]!='0') f[1][1]=1;else f[1][1]=0;
            for(int j=2;j<=n;++j) {//枚举每一行
            	f[j][0]=f[j][1]=0;
                if(s[j-1]=='0') {
                    if(a[j][i]!='1') f[j][0]|=f[j-1][0]|f[j-1][1];
                    if(a[j][i]!='0') f[j][1]|=f[j-1][1],f[j][0]|=f[j-1][0];
                }
                else {
                	if(a[j][i]!='1') f[j][0]|=f[j-1][0],f[j][1]|=f[j-1][1];
                    if(a[j][i]!='0') f[j][1]|=f[j-1][0]|f[j-1][1];
                }
            }
            if(f[n][0]&&f[n][1]) ans++;
		}
        if(ans<64) {
        	printf("%lld\n",1ll<<ans);
        }
        else puts("18446744073709551616");
	}
    return 0;
}

round 3

t1

题目内容

给定\(n\)\(a_1,a_2,\cdots a_n\)

你需要求出最小的自然数\(k\)使得\(a_1,a_2,\cdots a_n\)中不存在\(2k\)且不存在\(2k+1\)

输入格式

第一行一个正整数\(n\)

第二行\(n\)个自然数表示\(a_1,a_2,\cdots a_n\)

输出格式

一行一个数表示答案。

提示

对于\(100\%\)的数据,保证\(n\leq 10^6, a_i\leq 10^9\)

更多样例请见下发文件。

sol:

对数组排序后,对于每一个 \(k\),从 \(a\) 中挨个排除,找到合法的解后接着停止,这样的复杂度是线性的,瓶颈在 sort

code:

#include<bits/stdc++.h>
#define int long long
#define il inline
using namespace std;
const int N=1e6+10;
int n,a[N],f,k,tp;
il int read() {
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
il int Min(int x,int y){return x<y?x:y;}
signed main() {
//	freopen("ex_array.in","r",stdin);
	n=read();
	for(int i=1;i<=n;++i) {
		a[i]=read();
	}
	sort(a+1,a+1+n);
	n=unique(a+1,a+1+n) - a- 1;
	if(a[1]>1) {
		puts("0");
		return 0;
	}
	tp=1;
	while(!f&&tp<n) {
		while(a[tp]<(k*2)) ++tp;
		if((k<<1)<a[tp]&&(k<<1|1)<a[tp]) {
			f=1;
			break;
		}
		++k;
	}
	printf("%lld\n",k);
    return 0;
}

t2

题目内容

给定一个长为\(n\)的数列\(a_1,a_2,\cdots a_n\),以及正整数\(k\)

你需要求出\(a\)中有多少非空子序列满足:

子序列中元素的最大公约数\(\times\)子序列长度=k。

一个数列的子序列指的是将这个数列中的一些元素删去所得到的新数列。两个子序列不同当且仅当所删去数的位置集合不同。

由于答案可能很大,你需要将答案对\(10^9+7\)取模。

输入格式

第一行两个正整数\(n,k\)

第二行\(n\)个正整数表示\(a_1,a_2,\cdots a_n\)

输出格式

一行一个数表示答案。

提示

对于\(100\%\)的数据,保证\(n,k,a_i\leq 5\times 10^5\)

更多样例请见下发文件。

sol:

考虑枚举子序列长度 \(s\),要求的是,长度为 \(s\) \(\gcd\)\(\frac{k}{s}\) 的序列有多少。

posted @ 2023-11-07 21:46  XYini  阅读(7)  评论(0)    收藏  举报