比赛连接:Dashboard - The 2022 ICPC Asia Hangzhou Regional Programming Contest - Codeforces
A. Modulo Ruins the Legend
题目大意:
给你一个长度为n的数组,确定s,d的值,对于数组第k个元素ak加上s+kd,k∈[1,n],使得加上后数组的和模m后值最小。
0<=s<m;0<=d<m;如果多解输出任意一个满足条件的即可。
n,m (1≤n≤10^5, 1≤m≤10^9).
思路:
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=9901;
const int N=25;
int gcd(int a,int b)
{
if(!b) return a;
return gcd(b,a%b);
}
int exgcd(int a,int b,int &x,int &y)
{
if(!b){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
void solve()
{
int n,m,x,y,sum=0;
cin>>n>>m;
rep(i,0,n){
cin>>x;
sum=(sum+x)%m;
}
int s,d;
int g0=exgcd(n%m,1ll*n*(n+1)/2%m,s,d);
if(sum==0||g0==0){
cout<<0<<endl<<0<<" "<<0<<endl;
return;
}
int g=g0,ans,t=sum;
while(1){
g=gcd(g,m);
if(t%g==0){
ans=0;
break;
}
if(g>t){
ans=t;
break;
}
t%=g;
}
int T=((ans-sum)%m+m)%m;
g=exgcd(g0,m,x,y);
x=1ll*x*T/g%m;
x=(x+m)%m;
s=1ll*s*x%m,d=1ll*d*x%m;
s=(s+m)%m,d=(d+m)%m;
cout<<ans<<endl;
cout<<s<<" "<<d<<endl;
}
int main()
{
// #ifndef ONLINE_JUDGE
// freopen("title.in","r",stdin);
// freopen("title.out","w",stdout);
// #endif
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
//cin>>_;
while(_--){
solve();
}
return 0;
}
C. No Bug No Game
题目大意:
给定n个物品和限定k,要求最大化分数。物品的选择顺序可以任意。
第i物品一行pi代表个数,后面pi个wij代表容量(不一定递增),记录sum为∑pj (1≤j<i),对于第i个物品:
- sum+pi≤k 得到w(i,pi)的分
- sum≥k, 不能再加分了。
- 否则得到w(i,k−sum)分。
1≤n≤3000, 0≤k≤3000
1≤pi≤10;1≤wi,j≤10^5
思路:
简单的背包问题变型,可以将sum看做是背包容量,在k之内做动态规划。区别就是如果sum+pi>k,就会有一个物品不选满(选到刚好达到k的容量并得到相应的价值)。
用f[i][j][z]表示从前i个物品当中选,总和刚好为j,且z=0表示所有物品选满,z=1表示有一个没有选满的物品。转移方程见代码。
最后在枚举更新答案的时候需要判断j==k的时候才可以更新f[i][j][1]这个情况。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=9901;
const int N=3005;
int f[N][N][2],w[15];
void solve()
{
int n,k,p;
cin>>n>>k;
MEM(f,-0x3f);
f[0][0][0]=0;
rep(i,1,n+1){
cin>>p;
rep(j,1,p+1) cin>>w[j];
per(j,k-1,-1){
f[i][j][0]=f[i-1][j][0];
f[i][j][1]=f[i-1][j][1];
if(j+p<=k) f[i][j+p][0]=max(f[i][j+p][0],f[i-1][j][0]+w[p]),f[i][j+p][1]=max(f[i][j+p][1],f[i-1][j][1]+w[p]);
rep(z,1,p) if(j+z<=k) f[i][j+z][1]=max(f[i][j+z][1],f[i-1][j][0]+w[z]);
}
}
int ans=0;
rep(i,1,n+1) rep(j,0,k+1){
ans=max(ans,f[i][j][0]);
if(j==k) ans=max(ans,f[i][j][1]);
}
cout<<ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("title.in","r",stdin);
freopen("title.out","w",stdout);
#endif
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
//cin>>_;
while(_--){
solve();
}
return 0;
}
D. Money Game
题目大意:
n个人玩游戏,第i个人初始值为ai;每一轮会进行:从前往后,前一个人把他的值一半给后一个人,最后一个会给第一个。
问经过2022^1204轮之后,输出每个人的值,误差在10^-6之内。
2≤n≤10^5
1≤ai≤10^6
思路:
打表可以看出经过很多轮次后,最后满足a1=2*a2=...=2*an,而且整个序列的和不会因为操作而改变。数值的和记为s,当次数趋于无穷时,第一个数为2s/(n+1),后面都是s/(n+1)。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=9901;
const int N=25;
void solve()
{
int n;
db s=0;
cin>>n;
rep(i,0,n){
db x;
cin>>x;
s+=x;
}
s/=(n+1);
rep(i,0,n) if(i) printf("%.7lf ",s); else printf("%.7lf ",2*s);
}
int main()
{
// #ifndef ONLINE_JUDGE
// freopen("title.in","r",stdin);
// freopen("title.out","w",stdout);
// #endif
//ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
//cin>>_;
while(_--){
solve();
}
return 0;
}
E. Oscar is All You Need
题目大意:
T组测试,每组给定一个n,和1-n的排列,可以最多操作2*n+1次,每次操作将数组分为非空的三个部分,交换第一个和第三个部分。问字典序最小序列。输出操作次数和方案。(不要求操作次数最小)
1≤T≤120
3≤n≤1000
思路:
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=9901;
const int N=1010;
int n,a[N],b[N],sz;
pii p[2*N+5];
int got(int x)
{
rep(i,1,n+1) if(a[i]==x) return i;
}
void op(int l,int r)
{
p[++sz]={l-1,n-r};
int cnt=0;
rep(i,r+1,n+1) b[++cnt]=a[i];
rep(i,l,r+1) b[++cnt]=a[i];
rep(i,1,l) b[++cnt]=a[i];
rep(i,1,n+1) a[i]=b[i];
}
void solve()
{
cin>>n;
rep(i,1,n+1) cin>>a[i];
if(n==3){
if(a[1]>a[3]) cout<<1<<endl<<1<<" "<<1<<endl;
else cout<<0<<endl;
return;
}
sz=0;
int k=got(1);
if(k!=1){
if(k==2) op(3,3),op(n-1,n-1);
else op(k-1,k-1);
}
rep(i,2,n-1){
k=got(i);
if(k==i) continue;
if(k==i+1) op(i,i+1),op(n-i+1,n-i+1);
else op(i,i),op(k-i,n-i+1);
}
if(a[n-1]!=n-1) op(n-2,n-1),op(2,2),op(2,n-1),op(n-1,n-1),op(2,3);
cout<<sz<<endl;
rep(i,1,sz+1) cout<<p[i].fi<<" "<<p[i].se<<endl;
}
int main()
{
// #ifndef ONLINE_JUDGE
// freopen("title.in","r",stdin);
// freopen("title.out","w",stdout);
// #endif
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
return 0;
}
F. Da Mi Lao Shi Ai Kan De
题目大意:
有n各组,每组给一些字符串,从组中选择含有字串"bie"的加入到一组中(如果存在了不加了),如果可以添加就输出这个字符串,否则输出“Time to play Genshin Impact, Teacher Rice!”
思路:
水题,用string和set模拟即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=9901;
const int N=25;
set<string>st;
void solve()
{
int n;
bool f=0;
cin>>n;
while(n--){
string s;
cin>>s;
if(s.find("bie")!=-1&&st.find(s)==st.end()){
cout<<s<<endl;
st.insert(s),f=1;
}
}
if(!f) cout<<"Time to play Genshin Impact, Teacher Rice!"<<endl;
}
int main()
{
// #ifndef ONLINE_JUDGE
// freopen("title.in","r",stdin);
// freopen("title.out","w",stdout);
// #endif
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
return 0;
}
K. Master of Both
题目大意:
给定n个字符串,q此询问,每一次询问都定义一个字母字典序大小规则,在这种大小规则下求n个字符串逆序对的个数。
1≤n≤5×10^5, 1≤q≤5×10^4
思路:
在比较两个字符串的时候,只需要比较第一个不相同字母的大小就可以了。建立trie树,在建树的过程中维护cnt[p]的值,表示以p为前缀的字符串个数。再用inv[i][j]记录序列中(j,i)的对数个数。
注意有一种特殊情况需要单独算:当一个字符串插入完后,要加上其所有的子节点。因为它可能是前面字符串的一个前缀,这种情况它一定会和这些字符串构成逆序对。
最后计算答案就是两重循环,每次加上预处理出来的inv[i][j] (j>i)即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const int N=1e6+10;
int tr[N][26],idx=1;
LL tot,cnt[N],inv[26][26];
string s;
void ins()
{
int p=1;
++cnt[p];
rep(i,0,s.size()){
int j=s[i]-'a';
rep(k,0,26) if(j!=k) inv[j][k]+=cnt[tr[p][k]];
if(tr[p][j]==0) tr[p][j]=++idx;
p=tr[p][j],++cnt[p];
}
rep(i,0,26) tot+=cnt[tr[p][i]];
}
void solve()
{
int n,q;
cin>>n>>q;
while(n--){
cin>>s;
ins();
}
while(q--){
LL ans=0;
cin>>s;
rep(i,0,s.size()) rep(j,i+1,s.size()) ans+=inv[s[i]-'a'][s[j]-'a'];
cout<<ans+tot<<endl;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("title.in","r",stdin);
freopen("title.out","w",stdout);
#endif
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
//cin>>_;
while(_--){
solve();
}
return 0;
}
开坑开坑~~~
由于期末考试压力,其他题目待补题qwq,后面会持续更新~