2019四川省赛——解题报告(A,B,G,H,I,J)
作者:互联网
oj: 链接
2021/3/10 训练赛
A. Autochess
oj: 链接
题解
题意有点难懂,不过还能理解,而且还有点坑。
读懂题后,发现最难维护的点在于怎么快速找到最左边空着的位置。
我们的做法是二分+树状数组维护,同时用
m
a
p
map
map维护每个字符串的所有位置
树状数组维护非空位置的个数,这样就可以二分出最左边空着的位置,
然后再根据当前插入的字符串模拟并维护
m
a
p
map
map和树状数组即可。
其实想法不是特别难,不过题意有点坑,(所幸队友没被坑到。。)
代码
#include <bits/stdc++.h>
#define m_p make_pair
#define _for(i, a) for(int i = 0, len = (a); i < len; ++i)
#define _rep(i, a, b) for(int i = (a), len = (b); i <= len; ++i)
#define outval(a) cout << "debuging|" << #a << ":" << a << "\n";
#define dg if(debug)
#define sc(x) scanf("%d", &x)
#define scl(x) scanf("%lld", &x)
#define mem0(x) memset(x, 0, sizeof(x))
#define lowbit(x) (x & (-x))
using namespace std;
int debug = 0;
const int maxn = 100005;
const int inf = 0x3f3f3f3f;
typedef long long LL;
inline LL read() {
LL x(0), f(1); char c(getchar());
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
struct poi{
};
int n, m, k;
string s;
map< string, vector<int> > mp;
vector<string> ans;
int dat[maxn];
void insert(int p, int x) {
while(p <= m) {
dat[p] += x;
p += lowbit(p);
}
}
int query(int p) {
int ans = 0;
while(p) {
ans += dat[p];
p -= lowbit(p);
}
return ans;
}
int leftmost() {
int l = 1, r = m, ans = m + 1;
while(l <= r) {
int mid = (l + r) >> 1;
int tem = query(mid);
if(query(mid) < mid) {
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
return ans;
}
void init() {
mem0(dat);
mp.clear();
ans.resize(m + 1);
_rep(i, 1, m) ans[i] = "";
_rep(i, 1, m) dat[i] = 0;
}
int sol(int ttt) {
init();
int np = 0;
_rep(i, 1, n) {
string s;
cin >> s;
if(mp.count(s + "3")) continue;
if((mp[s].size() + 1) % k && np == m) continue;
int t = leftmost();
// if(t > m) continue;
insert(t, 1);
mp[s].push_back(t);
++np;
if(mp[s].size() == k) {
dg {
cout << "s:" << s << "\tpos:";
for(auto i : mp[s]) cout << " " << i;
cout << "\n";
}
for(int i : mp[s]) insert(i, -1);
mp.erase(mp.find(s));
np -= k - 1;
int t = leftmost();
insert(t, 1);
s.push_back('2');
mp[s].push_back(t);
if(mp[s].size() == k) {
for(int i : mp[s]) insert(i, -1);
mp.erase(mp.find(s));
np -= k - 1;
s[s.size() - 1] = '3';
int t = leftmost();
insert(t, 1);
mp[s].push_back(t);
}
}
}
cout << "Case " << ttt << ":";
for(auto i : mp) {
for(int j : i.second) {
ans[j] = i.first;
}
}
_rep(i, 1, m) {
if(ans[i].size() != 0) {
cout << " " << ans[i];
}
else cout << " -1";
}
cout << "\n";
return 0;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// debug = 1;
#endif
int T;
cin >> T;
_for(i, T) {
cin >> n >> m >> k;
sol(i + 1);
}
return 0;
}
B. Bin Packing
oj: 链接
题解
直接暴力枚举四种情况维护答案即可。
1.两个都竖着
2.两个都横着
3.一个横着一个竖着(两种情况)
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register 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<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#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 = 1e5+7;
double calc(int x1,int y1,int x2,int y2){
double ans=x1*y1+x2*y2;
if(y1>y2) ans+=(y1-y2)*x2*1.0/2;
else ans+=(y2-y1)*x1*1.0/2;
return ans;
}
int kcase=0;
void solve(){
int w1=read(),h1=read();
int w2=read(),h2=read();
double ans1=min(calc(w1,h1,w2,h2),calc(w1,h1,h2,w2));
double ans2=min(calc(h1,w1,w2,h2),calc(h1,w1,h2,w2));
printf("Case %d: %.6f\n",++kcase,min(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();
int T=read();
while(T--) solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
G. Game of Primes
oj: 链接
题解
感觉还算不是特别难想的博弈,而且也是挺经典的博弈思路。
首先把初始就能分出胜负的情况特判处理。
然后我们先考虑
B
o
b
Bob
Bob先手的情况:
当
(
x
,
y
)
(x,y)
(x,y)可以分解为
(
p
1
+
t
,
p
2
+
t
)
{
p
1
∈
P
r
i
m
e
,
p
2
∈
P
r
i
m
e
}
(p1+t,p2+t)\{p1\in Prime,p2\in Prime\}
(p1+t,p2+t){p1∈Prime,p2∈Prime},且
p
1
>
k
,
p
2
>
k
p1>k,p2>k
p1>k,p2>k时,
A
l
i
c
e
Alice
Alice必胜。
否则
B
o
b
Bob
Bob必胜。
原因:
每当
B
o
b
Bob
Bob选择减
x
x
x时,
A
l
i
c
e
Alice
Alice就选择减
y
y
y,
这样最后肯定是到
A
l
i
c
e
Alice
Alice必胜的条件。
然后我们考虑
A
l
i
c
e
Alice
Alice先手的情况,因为我们已经知道
A
l
i
c
e
Alice
Alice必胜的条件了,而且
A
l
i
c
e
Alice
Alice先手后紧接着就是
B
o
b
Bob
Bob先手了,即满足第一种情况。
那么我们只需要判断
A
l
i
c
e
Alice
Alice先手后的两种状态是否符合第一种情况,有的话
A
l
i
c
e
Alice
Alice肯定选择这种状态,因为这样能保证自己必胜。
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register 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<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#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 pA puts("Alice")
#define pB puts("Bob")
#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;
}
struct Prime {
vector<int> arr;
int vis[1000006];
void doit(int maxnum) {
for(int i = 2; i <= maxnum; ++i) {
if(!vis[i]) arr.push_back(i);
for(int j = 0; j < arr.size() && arr[j] * i <= maxnum; ++j) {
vis[arr[j] * i] = 1;
if(i % arr[j] == 0) break;
}
}
}
}P;
int x,y,k,w;
int check(int xx,int yy){
if(xx==k||yy==k) return 0;
if(!P.vis[xx]&&!P.vis[yy]) return 1;
rp(i,1,min(xx,yy))
if(xx-i>k&&yy-i>k&&!P.vis[xx-i]&&!P.vis[yy-i])
return 1;
return 0;
}
int kcase=0;
void solve(){
x=read(),y=read(),k=read(),w=read();
cout<<"Case "<<++kcase<<": ";
if(!P.vis[x]&&!P.vis[y]&&x!=k&&y!=k){
pA;
return ;
}
if(x==k||y==k){
pB;
return ;
}
if(!w){
// outval2(check(x-1,y),check(x,y-1));
if(check(x-1,y)||check(x,y-1)) pA;
else pB;
}
else{
if(check(x,y)) pA;
else pB;
}
}
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();
P.doit(1000007);
int T=read();
while(T--) solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
H. Hack a Contest
oj: 链接
题解
简单贪心题,直接按照每个问题的提交次数从大到小枚举,同时提交时间按照从大到小贪心取即可。
代码
#include <bits/stdc++.h>
#define m_p make_pair
#define _for(i, a) for(int i = 0, len = (a); i < len; ++i)
#define _rep(i, a, b) for(int i = (a), len = (b); i <= len; ++i)
#define outval(a) cout << "debuging|" << #a << ":" << a << "\n";
#define dg if(debug)
#define sc(x) scanf("%d", &x)
#define scl(x) scanf("%lld", &x)
using namespace std;
int debug = 0;
const int inf = 0x3f3f3f3f;
typedef long long LL;
inline LL read() {
LL x(0), f(1); char c(getchar());
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
struct poi{
};
const int N = 1e5+7;
int t[N],c[N];
int tt=1;
void sol() {
int n=read(),m=read();
_rep(i,1,n) t[i]=read();
sort(t+1,t+1+n,greater<int>());
_rep(i,1,m) c[i]=read();
sort(c+1,c+1+m,greater<int>());
LL ans=0;
int cur=1;
_rep(i,1,m){
ans+=t[cur]+1ll*20*(c[i]-1);
cur+=c[i];
}
cout<<"Case "<<tt++<<": "<<ans<<endl;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
debug = 1;
#endif
int T=read();
while(T--){
sol();
}
return 0;
}
I. Inventory
oj: 链接
题解
柯西不等式的模板题,
当然现场可能想不到,不过猜结论可能能够猜到。
这里提供一个猜结论的思路
第一个样例不好猜,我们考虑对第二个样例分析。
因为只有两个数都很小,所以我们可以考虑暴力枚举出接近正确答案的
v
1
,
v
2
v_{1},v_{2}
v1,v2。
近似得出
v
1
=
0.666666
,
v
2
=
1.333333
v_{1}=0.666666,v_{2}=1.333333
v1=0.666666,v2=1.333333。
可以发现
v
1
:
v
2
=
1
:
2
v_{1}:v_{2}=1:2
v1:v2=1:2。
然后我们考虑给的
x
1
=
2
,
x
2
=
8
x_{1}=2,x_{2}=8
x1=2,x2=8。
什么情况下通过这两个数的运算能够得到
1
:
2
1:2
1:2这个比值呢。
不难想到开根号刚好能够得出。
因此我们就构造出了这个样例,直接按照我们的这个思路(
v
v
v数组的比值等于
x
x
x数组每个元素开根号的比值)莽一发就行了。
证明(一般形式的柯西不等式):
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register 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<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#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 = 1e5+7;
int a[N];
int t;
void solve(){
int n=read(),V=read();
double ans=0;
rp(i,1,n){
a[i]=read();
ans+=sqrt(a[i]);
}
ans=ans*ans;
printf("Case %d: %.6f\n",++t,ans/V);
}
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();
int T=read();
while(T--) solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
J. Jump on Axis
oj: 链接
题解
我们先预处理出三种选择的前缀和,可以发现到
3000
3000
3000之后就大于
10000000
10000000
10000000了,因此我们直接暴力枚举第一种选择的和以及第二种选择的和,二分去找第三种选择的和即可。
我分了三种情况来处理:
1.有一种选择构成
2.有两种选择构成
3.有三种选择构成
最小步数不难维护,关键在于方案数,需要排列组合计算出来。
这里举有两个选择构成的例子:
假设一种选择有
x
x
x个数,另一种选择有
y
y
y个数,且这两个选择的所有数的和等于
k
k
k,那么方案数就是
C
x
+
y
x
C_{x+y}^{x}
Cx+yx。
三种选择的情况类推一下即可。
代码
#include <bits/stdc++.h>
#define m_p make_pair
#define _for(i, a) for(int i = 0, len = (a); i < len; ++i)
#define _rep(i, a, b) for(int i = (a), len = (b); i <= len; ++i)
#define outval(a) cout << "debuging|" << #a << ":" << a << "\n";
#define dg if(debug)
#define sc(x) scanf("%d", &x)
#define scl(x) scanf("%lld", &x)
#define mem0(x) memset(x, 0, sizeof(x))
#define lowbit(x) (x & (-x))
using namespace std;
int debug = 0;
const int maxn = 100005;
const int inf = 0x3f3f3f3f;
typedef long long LL;
inline LL read() {
LL x(0), f(1); char c(getchar());
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
struct poi{
};
const int N = 1e5+7;
const LL mod = 1e9+7;
int a1[N],a2[N],a3[N];
LL sum1[N],sum2[N],sum3[N];
vector<LL> s1,s2,s3;
LL fac[N];
void init(){
a1[1]=1;
_rep(i,2,N-7) a1[i]=a1[i-1]+3;
a2[1]=2;
_rep(i,2,N-7) a2[i]=a2[i-1]+3;
a3[1]=3;
_rep(i,2,N-7) a3[i]=a3[i-1]+3;
_rep(i,1,N-7){
sum1[i]=sum1[i-1]+a1[i];
if(sum1[i]>10000000) break;
s1.push_back(sum1[i]);
}
_rep(i,1,N-7){
sum2[i]=sum2[i-1]+a2[i];
if(sum2[i]>10000000) break;
s2.push_back(sum2[i]);
}
_rep(i,1,N-7){
sum3[i]=sum3[i-1]+a3[i];
if(sum3[i]>10000000) break;
s3.push_back(sum3[i]);
}
fac[0]=1;
_rep(i,1,N-7) fac[i]=(fac[i-1]*i)%mod;
}
LL quick_pow(LL a,LL b){
LL res=1;
while(b){
if(b&1) res=(res*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return res;
}
LL inv(LL x){
return quick_pow(x,mod-2)%mod;
}
LL C(int n,int m){
return fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod;
}
LL calc2(LL a,LL b){
return C(a+b,a)%mod;
}
LL calc3(LL a,LL b,LL c){
return C(a+b,a)*C(a+b+c,c)%mod;
}
void sol(int ttt) {
int K=read();
LL res1=inf;
LL res2=0;
LL num1=0;
int len1=s1.size(),len2=s2.size(),len3=s3.size();
//只有一个
int id=lower_bound(s1.begin(),s1.end(),K)-s1.begin();
if(id<len1&&s1[id]==K){num1++;res1=min(res1,1LL*(id+1));}
id=lower_bound(s2.begin(),s2.end(),K)-s2.begin();
if(id<len2&&s2[id]==K){num1++;res1=min(res1,1LL*(id+1));}
id=lower_bound(s3.begin(),s3.end(),K)-s3.begin();
if(id<len3&&s3[id]==K){num1++;res1=min(res1,1LL*(id+1));}
res2=(num1+res2)%mod;
if(debug) cout<<num1<<endl;
LL num2=0;
//只有两个
//1,2
_rep(i,1,K){
if(sum1[i]>=K) break;
LL temp=K-sum1[i];
int idd=lower_bound(s2.begin(),s2.end(),temp)-s2.begin();
if(idd<len2&&s2[idd]==temp){
num2=(num2+calc2(i,idd+1))%mod;
res1=min(res1,1LL*(i+(idd+1)));
}
}
//1,3
_rep(i,1,K){
if(sum1[i]>=K) break;
LL temp=K-sum1[i];
int idd=lower_bound(s3.begin(),s3.end(),temp)-s3.begin();
if(idd<len3&&s3[idd]==temp){
num2=(num2+calc2(i,idd+1))%mod;
res1=min(res1,1LL*(i+(idd+1)));
}
}
//2,3
_rep(i,1,K){
if(sum2[i]>=K) break;
LL temp=K-sum2[i];
int idd=lower_bound(s3.begin(),s3.end(),temp)-s3.begin();
if(idd<len3&&s3[idd]==temp){
num2=(num2+calc2(i,idd+1))%mod;
res1=min(res1,1LL*(i+(idd+1)));
}
}
res2=(res2+num2)%mod;
if(debug) cout<<num2<<endl;
//有三个
LL num3=0;
_rep(i,1,K){
if(sum1[i]>=K) break;
_rep(j,1,K){
if(sum2[j]>=K-sum1[i]) break;
LL temp=K-sum1[i]-sum2[j];
int idd=lower_bound(s3.begin(),s3.end(),temp)-s3.begin();
if(idd<len3&&s3[idd]==temp){
// dg cout<<i<<" "<<j<<" "<<idd<<endl;
num3=(num3+calc3(i,j,idd+1))%mod;
res1=min(res1,1LL*(i+j+(idd+1)));
}
}
}
dg cout<<num3<<endl;
res2=(res2+num3)%mod;
cout<<"Case "<<ttt<<": "<<res1<<" "<<res2<<endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// debug = 1;
#endif
init();
int T=read();
_rep(i,1,T) {
sol(i);
}
return 0;
}
标签:ch,return,四川省,int,LL,read,解题,2019,define 来源: https://blog.csdn.net/qq_43472263/article/details/114788001