2019年湘潭大學程序設計競賽(重現賽)
由於本人水平比較菜,只做出了5個,剩下的不太會了。寫簡單題的題解主要是給本校學弟學妹學習學習的。
A、B水題就不解釋了;
代碼比較醜,輕噴
A:A本來是想寫一個結構題排下序的,後來發現重載那裏比較難寫,就換了下面這一種
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,p,s;
int n1,p1,s1;
struct node
{
int id,x,y,z;
}a[3];
int main()
{
for(int i=1;i<=2;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
a[i].id=i;
}
if(a[1].x<a[2].x)
{
printf("2\n");
return 0;
}
if(a[1].x>a[2].x)
{
printf("1\n");
return 0;
}
if(a[1].y<a[2].y)
{
printf("1\n");
return 0;
}
if(a[1].y>a[2].y)
{
printf("2\n");
return 0;
}
if(a[1].z<a[2].z)
{
printf("1\n");
return 0;
}
if(a[1].z>a[2].z)
{
printf("2\n");
return 0;
}
printf("God\n");
return 0;
}
B:
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;cin>>t;
while(t--)
{
int n;int ans=0;
scanf("%d",&n);
while(n>1){
if(n%10!=0)
{
ans++;n++;
}
while(n%10==0){
n/=10;
ans++;
}
}
printf("%d\n",ans);
}
}
鏈接:https://ac.nowcoder.com/acm/contest/893/C
來源:牛客網
題目描述
已知整數a,a3a,a3除192的餘數是1。求區間[L,R]之間滿足條件的a的累加和是多少?
輸入描述:
第一行是一個整數T(1≤T≤10000)T(1≤T≤10000),表示樣例的個數。
每個樣例包含兩個整數L,R,1≤L≤R≤109L,R,1≤L≤R≤109。
輸出描述:
每行輸出一個樣例的結果。
示例1
輸入
1
1 10
輸出
1
C題打表找規律,還不會打表的看我代碼的註釋部分。
至於官方解法,不知道怎麼證的。
可以看看
然後還有一個知識點。如果是求(L,R);我們可以求這個(0,R)-(0,L-1)代替(L,R)。好好想想~
還有人找到規律不知道怎麼寫的嗎?
1,193,385,577.等差數都爲192.
1,192*1+1,192*2+1,192*3+1......以此類推(等差數列通項)。
先不考慮1,都減一個1.(待會加回來就可以了 加個(L-R+1))
0,192*1,192*2,192*3;
那麼只需要統計區間內192的個數*192(前面已經說了(0,R)-(0,L-1)代替(L,R))
這裏還有一個知識點。若R/192=num,那麼num就是0到R區間內包含192的個數(可以自己去證明幾個數玩玩)
那麼求出num了,答案就是num*(num+1)/2*192+(L-R+1).(num*(num+1)/2是等差數列求和,上了大學,高中知識快忘了吧,快去百度等差數列怎麼求和的)
數列就變成了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+10;
const ll inf=1e9;
ll sum[N*40];
int ls[N*40],rs[N*40];
int cnt=0,rt;
/*void init()
{
for(ll i=1;i<=1e3;i++)
{
if((i*i*i)%192==1)
{
printf("i:%lld\n",i);
}
}
}*/
int main()
{
int t;
//init();
cin>>t;
while(t--)
{
ll l,r;
scanf("%lld%lld",&l,&r);
ll n1=0,n2=0;
if(l>=2) n1=(l-2)/192;
if(r>=1) n2=(r-1)/192;
//printf("n1:%lld\n",n1);
//printf("n2:%lld\n",n2);
ll a1=n1*(n1+1)*192/2;
ll a2=n2*(n2+1)*192/2;
//printf("a2:%lld a1:%lld\n",a2,a1);
ll ans=a2-a1+n2-n1;
if(l==1) ans++;
printf("%lld\n",ans);
}
}
下面是許老師的代碼,多簡潔
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll gao(ll n)
{
int m=n/192;
if(n%192)
m++;
return 1ll*(1+192*(m-1)+1)*m/2;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int l,r;
cin>>l>>r;
ll ans=gao(r);
ans-=gao(l-1);
cout<<ans<<endl;
}
}
鏈接:https://ac.nowcoder.com/acm/contest/893/D
來源:牛客網
有n堆石子排成一排,第i堆石子有aiai個石子。
每次,你可以選擇任意相鄰的兩堆石子進行合併,合併後的石子數量爲兩堆石子的和,消耗的體力等價於兩堆石子中石子數少的那個。
請問,將所有的石子合併成一堆,你所消耗的體力最小是多少?
輸入描述:
第一行是一個整數T(1≤T≤20)T(1≤T≤20),表示樣例的個數。
每個樣例的第一行是一個整數n(1≤n≤10000)n(1≤n≤10000),表示石子堆的數量。
第二行是n個整數ai(1≤ai≤109)ai(1≤ai≤109)
輸出描述:
每行輸出一個樣例的結果。
示例1
輸入
2
2
1 2
1
1
輸出
1
0
說明
巨大的輸入,請使用C風格的輸入。
感覺題解講的很清楚了。管你是不是選擇相鄰的。我永遠從最大的那一堆跟它附近的堆合併。最大堆合併一個堆後還是最大的堆。那麼代價就不會加上最大堆的值。
所以我的做法是排個序,從1加n-1就可以了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e4+10;
ll a[N];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
ll x;
scanf("%lld",&a[i]);
}
ll ans=0;
sort(a+1,a+1+n);
for(int i=1;i<=n-1;i++) ans+=a[i];
printf("%lld\n",ans);
}
}
鏈接:https://ac.nowcoder.com/acm/contest/893/F
來源:牛客網
題目描述
你有一個長度爲 n 的 01 串S,你可以執行最多 m 次操作。
對於每次操作,你可以選擇一個位置 i 滿足 1≤i≤n1≤i≤n,翻轉這一位的值,0變成1,1變成0。
定義一個 01 串的價值爲其中最長連續0的個數和最長連續1的個數的較大值,求S在經過最多m次操作後的最大價值。
輸入描述:
* 第一行一個整數 T ,表示接下來有 T 個樣例。
* 首先輸入n,m,表示S串的長度n和操作次數m,其中1≤n≤1000001≤n≤100000,0≤m≤10000≤m≤1000;
* 接下來輸入一個長度爲n的字符串S。
輸出描述:
一個整數,表示題面上描述的最大價值。
示例1
輸入
2
5 1
00101
2 1
01
輸出
4
2
說明
第一個串翻轉第三個位置,00001的價值爲4;第二個串翻轉第一個位置,11的價值爲2。
F題我的做法不太正確哈,我是純暴力。從每一個點出發,要麼向左延伸,要麼向右延伸,求最大值。時間複雜度:O(1e8);
正確做法請看官方題解:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
char s[N];
int t,a[N],n,m;
struct node
{
int x,y;
}b[N];
int call(int id,int m)
{
int pre=a[id];
int num=1;
int l=id-1,r=id+1;
while(m&&l>=1)
{
if(a[l]!=pre)m--;
num++;
l--;
}
while(l>=1&&a[l]==pre)l--,num++;
while(r<=n&&a[r]==pre) r++,num++;
return num;
}
int calr(int id,int m)
{
int pre=a[id];
int num=1;
int l=id-1,r=id+1;
while(m&&r<=n)
{
if(a[r]!=pre)m--;
num++;
r++;
}
while(l>=1&&a[l]==pre)l--,num++;
while(r<=n&&a[r]==pre) r++,num++;
return num;
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=n;i++) a[i]=s[i]-'0';
int ans=0;
for(int i=1;i<=n;i++)
{
int pre=a[i];
int num=0;
int a1=call(i,m);
int a2=calr(i,m);
num=max(a1,a2);
ans=max(ans,num);
}
printf("%d\n",ans);
}
}
/*
100
14 6
11110000001111
100
12 1
100001110111
15 1
000100001110111
*/
再貼一下正確做法的代碼,來自hsx
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int pref[105000];
int main(){
int t;
cin>>t;
while(t--){
int n,m;
cin>>n>>m;
string s;
cin>>s;
for(int i=0;i<n;i++){
if(s[i]=='1') pref[i+1]=pref[i]+1;//統計1的個數
else pref[i+1]=pref[i];
}
int ans=0;
for(int i=1;i<=n;i++){//這樣也闊以咯
int l=i;
int r=n;
while(l<=r){
int mid=(l+r)/2;
if(pref[mid]-pref[i-1] <= m){
ans=max(ans,mid-i+1);
l=mid+1;
}
else r=mid-1;
}
}
for(int i=1;i<=n;i++){
int l=i;
int r=n;
while(l<=r){
int mid=(l+r)/2;
if((mid-i+1) - (pref[mid]-pref[i-1]) <= m){//0的個數
ans=max(ans,mid-i+1);
l=mid+1;
}
else r=mid-1;
}
}
printf("%d\n",ans);
}
return 0;
}