The 2022 SDUT Summer Trials

The 2022 SDUT Summer Trials

1.Problem - A - Codeforces

结论:两个数分别除以他们的最大公约数,商是互质数。

void slove()
{
int x, y;
cin >> x >> y;
cout << __gcd(x,y) << endl;
}

2.Problem - B - Codeforces

可以用dp,定义dp[ i ]位以i结尾的最大价值。很明显转移方程就是找到第一个小于a[ i ]的 a[ j ]就可以,因为大于a[ i ] 的都要变成a[i]。

那如何找到j的位置,可以用一个单调栈维护单调递增的序列即可。我比你小又比你近你肯定就没有机会了。所以是单调递增。

dp[i]=dp[j]+(ji)a[i]

 

void slove()
{
int n;
cin >> n;
fel(i,1,n) cin >> a[i];
stack< pair<int,int> >s;
s.push({0, 0});
int ans=0;
for(int i = 1;i <= n; i++){
while(s.size()&&s.top().first>=a[i]) s.pop();
auto [x, y] = s.top();
f[i] = f[y] + ( i - y ) *a[i];
ans = max( ans, f[i] );
s.push({ a[i], i });
}
cout<<ans<<endl;
}

 

3.Problem - C - Codeforces

这属实是好题呀。写他的第二天碰到了一个差不太多的题目。

首先来看值域值域很小,抽屉原理明显的。最多1e5个值。所以直接考虑什么时候开始出现重复,很明显当数列长度为n的时候选择为2^n次方。考虑到这个,当n大于=17的时候是130000多 > 1e5所以当n大于17,肯定有解,所以就看小于17直接二进制枚举暴力求解即可。

void slove(){
cin >> n >> k;
fel(i,1,n) cin >> a[i];
if(n >= 17){
cout << "YES" << endl;
return;
}
int flag = 0;
for(int i = 1; i < (1<<n); i++){
int sum=0;
for(int j=1; j <= n; j++){
if(( i>>(j-1) ) & 1){
sum = (sum + a[j]) % k;
}
}
mp[sum]++;
if(mp[sum] > 1){
flag = 1;
break;
}
}
cout << (flag?"YES":"NO") << endl;
}

 

4.Problem - D - Codeforces

void slove()
{
cin >> n;
fel(i,1,n) cin >> a[i] >> k[i];
int ans = 0;
fel(i,1,n){
fel(j,i+1,n){
if(a[i] != a[j]){
ans++;
}
}
}
cout<<ans<<endl;
}

 

5.Problem - E - Codeforces

很明显奇数不行。考虑偶数。

看第一个例子发现每次可以确定一个点然后会确定一些相关的点。每个点的选择是2。最后就是2的m次方。

void slove(){
cin >> n;
int flag = 0;
fel(i,1,n)
{
cin >>  a[i];
if (a[i] == i) flag = 1;
}
if(n % 2 || flag){
cout<<0<<endl;
return;
}
int ans = 1;
for(int i = 1;i <= n; i++){
int j = i;
if(vis[j] == 0){
ans=(ans*2)%mod;
while(vis[j] == 0){
vis[j] = 1;
j = a[j];
}
}
}
cout<<ans<<endl;
}

 

6.Problem - F - Codeforces

不会写看的题解,感觉很莫名奇妙。我应该把所有情况都讨论了呀。

image-20221016143039836

而且答案是错的,应该输出1,2,3呀?感觉官方题解有个地方想错了。如果全是负数的话应该单独拿出来讨论。

首先如果存在奇数同时存在正数的话肯定考虑用那个去取一个最大正数,这样你肯定可以保证结果是更优的。然后剩余的k就每次取两个。因为负数取的个数肯定是偶数更优的。给出自己的代码吧,虽然错了,可能是出题人没想到这种情况。

bool cmp(node x,node y){
if(x.val==y.val){
if(x.val>=0){
return x.id>y.id;
}
else{
x.id<y.id;
}
}
return x.val<y.val;
}
bool cmp2(node x,node y){
if(x.val==y.val){
return x.id<y.id;
}
return x.val>y.val;
}
void slove(){
cin>>s;
cin>>k;
int len=s.length(),cnt=0;
for(int i=0;i<len;i++){
if(s[i]=='|') continue;
int j=i,sum=0,flag=1;
while(j<len&&s[j]!='|'){
if(s[j]=='-') flag=-1;
else{
sum=sum*10+(s[j]-'0');
}
j++;
}
j--;
i=j;
b[++cnt]={sum*flag,cnt};
a[cnt] = sum;
}
int n = cnt;
sort(b+1,b+1+cnt,cmp);
if(b[cnt].val<=0&&k%2==1){
sort(b+1,b+1+cnt,cmp2);
fel(i,1,k){
vis[b[i].id]=1;
}
for(int i=1;i<=n;i++){
if(vis[i]){
cout<<i<<" ";
}
}
cout<<endl;
return;
}
else{
int l = 1,r = n;
if(k&1){
vis[b[n].id]=1;
r--;
k--;
}
while(k){
int x = b[l].val * b[l+1].val;
int y = b[r].val * b[r-1].val;
int minn1 = min(b[l].id , b[l+1].id);
int minn2 = min(b[r].id , b[r-1].id);
if(x > y || ( x == y && minn1 < minn2 ) ){
vis[ b[l].id ] = 1;
vis[ b[l + 1].id ] = 1;
l += 2;
}
else{
vis[ b[r].id ] = 1;
vis[ b[r - 1].id ] = 1;
r -= 2;
}
k -= 2;
}
}
int f = 0;
fel(i , 1 , n){
if(vis[i] && !a[i] )  f = i;
}
if(f){
memset(vis,0,sizeof(vis));
vis[f] = 1;
int idx = 0;
cnt --;
while(cnt){
if( !vis[++idx] ){
cnt--;
vis[idx] = 1;
}
}
}
for(int i = 1 ; i <= n ; i++){
if( vis[i] ){
cout<<i<<" ";
}
}
}

7.Problem - G - Codeforces

背包是很明显的,刚开始写的时候不知道怎样处理把子序列插进去,实际上你想只要把剩余的给排好就可以了。然后这些直接插进去就好了。

背包直接考多重背包即刻。

void slove(){
cin>>n>>k;
fel(i,1,26) cin>>a[i];
cin>>s;
for(auto i:s){
a[i-'a'+1]--;
if(a[i-'a'+1]<0){
cout<<"NO SOLUTION!"<<endl;
return;
}
}
f[0][0]=1;
for(int i=1;i<=26;i++){
for(int j=k-n;j>=0;j--){
for(int w=0;w<=a[i];w++){
if(j<w) break;
else{
f[i][j]=(f[i][j]+f[i-1][j-w])%mod;
}
}
}
}
cout<<f[26][k-n]<<endl;
}

 

8.Problem - H - Codeforces

这不就纯模拟。

bool check(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=n&&vis[x][y]==0) return true;
return false;
}
void slove()
{
cin >> n;
fel(i,1,n){
fel(j,1,n){
cin >> a[i][j];
}
}
da = 0; db = 2;
int sx=1,sy=1,ex=n,ey=n;
vector<int>x,y;
x.pb(a[1][1]);
y.pb(a[n][n]);
vis[1][1]=1,vis[n][n]=1;
while(x.size()+y.size()<n*n){
int t1=sx+dx[da],t2=sy+dy[da];
if(check(t1,t2)){
vis[t1][t2]=1;
x.pb(a[t1][t2]);
sx=t1,sy=t2;
}
else{
da=(da+1)%4;
}
t1=ex+dx[db],t2=ey+dy[db];

if(check(t1,t2)){
vis[t1][t2]=1;
y.pb(a[t1][t2]);
ex=t1,ey=t2;
}
else{
db=(db+1)%4;
}
}
for(auto i:x){
cout<<i<<" ";
}
cout<<endl;
for(auto i:y){
cout<<i<<" ";
}
}

 

9.Problem - I - Codeforces

这个题也是看题解写的,首先看懂题确实有点hard。是一定可以找出那个bad 天平。很明显如果是指数级别的减少一定是最快找出来的。

考虑什么样子可以指数级别的减少。考虑如果有三堆,两堆上称就可以确定是那一堆了。所以考虑小于等于3*n的时候可以用种策略。

那再考虑大于三堆的可以直接每次去掉2*n

void slove(){
cin>>n>>m;
if(m<=3*n){
int ans=0;
while(m>1){
ans++;
m=(m+2)/3;
}
cout<<ans<<endl;
}
else{
int ans=(m-3*n+2*n-1)/(2*n);
//cout<<ans<<endl;
m=m-ans*2*n;
while(m>1){
ans++;
m=(m+2)/3;
}
cout<<ans<<endl;
}
}

 

10.Problem - J - Codeforces

二分图板子。

bool find(int u){
for(auto v:b[u]){
if(!vis[v]){
vis[v]=1;
if(match[v]==0||find(match[v])){
match[v]=u;
return 1;
}
}
}
return 0;
}
void slove(){
cin>>n>>m>>q;
int cnt=0;
fel(i,1,q){
string a,c;
cin>>a;
cin>>c;
if(!mp.count(a)) mp[a]=++cnt;
if(!mp.count(c)) mp[c]=++cnt;//就是给每个字符一个下标
b[mp[a]].push_back(mp[c]);
s.insert(mp[a]);
}
int ans=0;
for(auto i:s){
memset(vis,0,sizeof(vis));
if(find(i)) ans++;
}
cout<<ans<<endl;
}

 

11.Problem - L - Codeforces

直接爆搜即可。

inline void dfs(int sta,int p,int co){//co*x^p//每一项必须乘以后面的每一项中找一项
if(sta==n+1){
ans[p]+=co;
}
for(auto [x,y]:mp[sta]){
dfs(sta+1,p+x,co*y);
}
}
void slove(){
cin>>n>>q;
fel(i,1,n) cin>>f[i];
fel(i,1,n){
mp[i][0]=1;
mp[i][f[i]/2]=-1;
mp[i][f[i]]=-1;
}
dfs(1,0,1);
while(q--){
int x;
cin>>x;
cout<<ans[x]<<endl;
}
}
 
posted @   silky__player  阅读(127)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示