湘潭大學2017年下學期程式設計實踐-模擬測試1 題解
XTU 1284 多項式
思路:直接迴圈求解便可,注意長整型溢位的問題
(a+b)%m = a%m + b%m
可根據這個式子求解,另外注意多次方有可能溢位LL。
#include <bits/stdc++.h>
using namespace std;
#define ll __int64
int n,m,x;
int a[100];
ll qpow(ll a,ll n)//記得每次要對值取模
{
ll ret=1;
while(n)
{
if(n&1)
ret=ret*a%m;
a=a*a %m;
n>>=1;
}
return ret;
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d%d%d",&n,&m,&x);
ll ans = 0;
for(int i=n;i>=0;i--)
{
scanf("%d",a+i);
ans = (ans + (ll)a[i]*(ll)qpow(x,i))%m ;
}
cout<<ans<<"\n";
}
return 0;
}
XTU 1285 探測器
思路:只要從左到右依次遍歷,遇到“0”就計數,並且把相鄰的全都改成“1”,這樣保證結果最優。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
char s[100];
scanf("%s",s);
int len=strlen(s);
int ans=0;
for(int i=0;i<len;i++)
{
if(s[i]=='0')
{
for(int j=max(0,i-2);j<=min(len-1,i+2);j++)
{
s[j]='1';
}
ans++;
}
}
cout<<ans<<endl;
}
return 0;
}
XTU 1286 比賽
思路:
我們要讓冠軍(假設為1號)打儘量多的比賽,那麼就要儘量多的給1號創造對手,根據題意可知:
要創造一個0級的對手不需要額外消耗
創造一個1級對手需要額外消耗1個0級的對手
而冠軍(1號)想要升到2級,只需要搞定2個0級的對手:0 vs 0 和 1 vs 0
根據前面的推斷可知,打的對手等級越低,消耗的對手人數越少,從而能讓1號打儘可能多的比賽。
因此
1號的等級 對手的等級
0 0
1 0
2 1
3 2
…
而我們可知:
對手要上1級,需要2個0級的對打
對手要上2級,需要1個1級打敗1個0級
對手要上3級,需要1個2級打敗一個1級
……
於是見程式碼:
#include <bits/stdc++.h>
using namespace std;
#define ll __int64
ll csa[1000];
void init()
{
//csa[i]表示產生一個等級i的對手需要消耗多少對手。
csa[0]=1;
csa[1]=2;
for(int i=2;i<1000;i++)
{
csa[i] = csa[i-1]+csa[i-2];
}
}
int main()
{
init();
ll n;
while(cin>>n)
{
n--;
int ans=0;
if(n==0)
{
;
}
else if(n==1)
{
ans++;
}
else if(n==2)
{
ans+=2;
}
else
{
n-=2;
ans+=2;
for(int i=2;n>=0;i++)
{
if(csa[i-1]<=n)
ans++;
n-=csa[i-1];
}
}
cout<<ans<<endl;
}
return 0;
}
XTU 1287 銀行
思路:
一天一共24*60分鐘,所以只需要遍歷每一分鐘發生了什麼便可,這裡需要熟練掌握優先佇列的操作(主要是優先順序的確定)
細節題,詳見程式碼
#include <bits/stdc++.h>
using namespace std;
struct node
{
string id;//編號
int i;//是當天第一個到銀行的
int s;//什麼時候到達銀行的
int t;//辦理時長
int d;//最長等待時長
int wt;//等了多久
bool ok;//等到沒有
node(){}
node(string id,int i,int s,int t,int d):id(id),i(i),s(s),t(t),d(d),ok(0){}
friend bool operator < (node a,node b)
{
if(a.id[0]!=b.id[0])
{
return a.id[0]!='V';
}
return a.s>b.s;
}
}p[300];
int main()
{
int cnt=1;
string id;
int h,m;
int t;
int d;
char c;
while(cin>>id>>h>>c>>m>>t>>d)
//讀入資料,把時間處理成h*60+m的形式
p[cnt++]=node(id,cnt,h*60+m,t,d);
priority_queue<node> pq;
int qwq=1;
int nows=0;
for(int i=0;i<=3600;i++)//遍歷每一分鐘
{
while(p[qwq].s<=i && qwq<cnt)
//當此時此刻,顧客已經到達銀行了,則加入佇列,進行排隊
pq.push(p[qwq++]);
if(nows<=i)
{
while(!pq.empty() && pq.top().s + pq.top().d < nows )
pq.pop();//當等了d分鐘還沒有排到,離開佇列
if(pq.empty())continue;
node tmp = pq.top();//隊首的顧客排到了
pq.pop();
p[tmp.i].ok=1;
p[tmp.i].wt=i - tmp.s;
nows = i + tmp.t;
}
}
for(int i=1;i<cnt;i++)
{
cout<<p[i].id<<" ";
if(p[i].ok)
cout<<p[i].wt<<" Yes\n";
else cout<<p[i].d<<" No\n";
}
return 0;
}
XTU 1288 Binary Search Tree
思路:暴力建樹然後暴力匹配,檢視是否同構
主要考察BST應用能力。
不能動態指標建樹,若不釋放記憶體,會MLE;釋放記憶體會TLE;
不能陣列建樹,n到達了100,所以最大樹到達了2的100次方;
綜上,用靜態指標。
#include <bits/stdc++.h>
using namespace std;
struct node
{
int v;
node *l,*r;
void init()
{
l=r=0;
}
}tree1[10005],tree2[10005];
int cnt,cnt2;
inline node* newnode1(int val)
{
tree1[cnt].init();
tree1[cnt].v=val;
return &tree1[cnt++];
}
inline node* newnode2(int val)
{
tree2[cnt2].init();
tree2[cnt2].v=val;
return &tree2[cnt2++];
}
void build(node* u,int val)
{
if(val < u->v)
{
if(u->l!=NULL)
build(u->l,val);
else
u->l = newnode1(val);
}
else
{
if(u->r!=NULL)
build(u->r,val);
else
u->r = newnode1(val);
}
}
void build2(node* u,int val)
{
if(val < u->v)
{
if(u->l!=NULL)
build2(u->l,val);
else
u->l = newnode2(val);
}
else
{
if(u->r!=NULL)
build2(u->r,val);
else
u->r = newnode2(val);
}
}
bool _istongG(node* t1,node* t2)
{
if(t1==NULL || t2==NULL)
return t1==NULL && t2==NULL;
return _istongG(t1->l, t2->l) && _istongG(t1->r, t2->r);
}
int main()
{
int t;
int n,m;
cin>>t;
int a[1001];
while(t--)
{
cnt=1;
scanf("%d%d",&n,&m);
scanf("%d",&a[1]);
node *root = newnode1(a[1]);
for(int i=2;i<=n;i++)
{
scanf("%d",a+i);
build(root,a[i]);
}
for(int i=1;i<=m;i++)
{
cnt2=1;
scanf("%d",&a[1]);
node *root2 = newnode2(a[1]);
for(int j=2;j<=n;j++)
{
scanf("%d",a+j);
build2(root2,a[j]);
}
printf("%d: %s",i,((_istongG(root,root2))?"Yes\n":"No\n"));
}
cout<<endl;
}
return 0;
}
XTU 1289 3的倍數
暫時沒做…好難啊
UPD:
XTU 1289 3的倍數
思路:
1.我們知道,一個數字是3的倍數,當且僅當這個數字的數位和能整除3,那麼我們只需要找出那些使得數位和能整除3的種類。
2.
dp[i][j]表示以第i個數字為數字的開頭,能構成多少種符合條件的數字(此時不考慮前導0)
那麼有遞推式:
①:當前位模3餘0:
dp[i][0]=dp[i+1][0]<<1|1;
dp[i][1]=dp[i+1][1]<<1;
dp[i][2]=dp[i+1][2]<<1;
②:當前位模3餘1:
dp[i][0]=dp[i+1][0]+dp[i+1][2];
dp[i][1]=dp[i+1][1]+dp[i+1][0]+1;
dp[i][2]=dp[i+1][2]+dp[i+1][1];
③:
dp[i][0]=dp[i+1][0]+dp[i+1][1];
dp[i][1]=dp[i+1][1]+dp[i+1][2];
dp[i][2]=dp[i+1][2]+dp[i+1][0]+1;
此時,對於這個數字,dp[0][0]就是要求的答案。
3.問題在於如何去除含有前導0的種類數:
對於s[i]==0:
它的種類數應該是dp[i+1][0]+1;
(當前位是0,後面要湊成3的倍數,共有dp[i+1][0]種,然後後面全部不選,只選第i也滿足,故種類數是dp[i+1][0]+1)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
int main()
{
char s[10000];
int v[10000];
ll dp[10000][3];
while(scanf("%s",s)!=EOF)
{
int len=strlen(s);
for(int i=0;i<len;i++)
v[i] = (s[i]-'0')%3;
dp[len][0]=dp[len][1]=dp[len][2]=0;
for(int i=len-1;i>=0;i--)
{
if(v[i]==0)
{
dp[i][0]=dp[i+1][0]<<1|1;
dp[i][1]=dp[i+1][1]<<1;
dp[i][2]=dp[i+1][2]<<1;
}
else if(v[i]==1)
{
dp[i][0]=dp[i+1][0]+dp[i+1][2];
dp[i][1]=dp[i+1][1]+dp[i+1][0]+1;
dp[i][2]=dp[i+1][2]+dp[i+1][1];
}
else
{
dp[i][0]=dp[i+1][0]+dp[i+1][1];
dp[i][1]=dp[i+1][1]+dp[i+1][2];
dp[i][2]=dp[i+1][2]+dp[i+1][0]+1;
}
dp[i][0]%=mod;dp[i][1]%=mod;dp[i][2]%=mod;
}
ll ans=dp[0][0];
for(int i=1;i<len;i++)
{
if(s[i]=='0')
{
ans = ans-dp[i+1][0]-1;
ans%=mod;
}
}
cout<<(ans+mod)%mod<<"\n";
}
return 0;
}