XTU 1284 多项式
http://202.197.224.59/exam/index.php/problem/exam_read/id/1284/exam_id/227
思路:直接循环求解便可,注意长整型溢出的问题
(a+b)%m = a%m + b%m
可根据这个式子求解,另外注意多次方有可能溢出LL。
#include
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<"\n";
}
return 0;
}
XTU 1285 探测器
http://202.197.224.59/exam/index.php/problem/exam_read/id/1285/exam_id/227
思路:只要从左到右依次遍历,遇到“0”就计数,并且把相邻的全都改成“1”,这样保证结果最优。
#include
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;iif(s[i]=='0')
{
for(int j=max(0,i-2);j<=min(len-1,i+2);j++)
{
s[j]='1';
}
ans++;
}
}
cout<return 0;
}
XTU 1286 比赛
http://202.197.224.59/exam/index.php/problem/exam_read/id/1286/exam_id/227
思路:
我们要让冠军(假设为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
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<return 0;
}
XTU 1287 银行
http://202.197.224.59/exam/index.php/problem/exam_read/id/1287/exam_id/227
思路:
一天一共24*60分钟,所以只需要遍历每一分钟发生了什么便可,这里需要熟练掌握优先队列的操作(主要是优先级的确定)
细节题,详见代码
#include
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 pq;
int qwq=1;
int nows=0;
for(int i=0;i<=3600;i++)//遍历每一分钟
{
while(p[qwq].s<=i && qwq//当此时此刻,顾客已经到达银行了,则加入队列,进行排队
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;icout<" ";
if(p[i].ok)
cout<
" Yes\n";
else cout<
" No\n";
}
return 0;
}
XTU 1288 Binary Search Tree
http://202.197.224.59/exam/index.php/problem/exam_read/id/1288/exam_id/227
思路:暴力建树然后暴力匹配,查看是否同构
主要考察BST应用能力。
不能动态指针建树,若不释放内存,会MLE;释放内存会TLE;
不能数组建树,n到达了100,所以最大树到达了2的100次方;
综上,用静态指针。
#include
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<return 0;
}
XTU 1289 3的倍数
http://202.197.224.59/exam/index.php/problem/exam_read/id/1289/exam_id/227
暂时没做…好难啊
UPD:
XTU 1289 3的倍数
http://202.197.224.59/exam/index.php/problem/read/id/1289
思路:
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
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'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;iif(s[i]=='0')
{
ans = ans-dp[i+1][0]-1;
ans%=mod;
}
}
cout<<(ans+mod)%mod<<"\n";
}
return 0;
}