牛客算法周周练2
A
#include<bits/stdc++.h>
#define sc(x) scanf("%lld",&x);
#define pf printf
#define rep(i,s,e) for(int i=s;i<=e;i++)
#define dep(i,e,s) for(int i=e;i>=s;i--)
using namespace std;
typedef long long ll;
const int inf=~0u>>2;
const int maxn=1e5+7;
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int main()
{
SIS;
//¼ÓËÙcin/cout
int n,k;
cin>>n;
k=n;
int t=0;
while(n)
{
int k=n%10;
t = t*10+k;
n=n/10;
}
cout<<k+t<<endl;
return 0;
}
C
打个表出来,然后用lower_bound(返回第一个大于等于该元素的数)然后,计算个数,范围其实不大,注意查找得用二分,不然会TLE
代码:
#include<bits/stdc++.h>
#define sc(x) scanf("%lld",&x);
#define pf printf
#define rep(i,s,e) for(int i=s;i<=e;i++)
#define dep(i,e,s) for(int i=e;i>=s;i--)
using namespace std;
typedef long long ll;
const int inf=~0u>>2;
const int maxn=1e5+7;
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
ll b[maxn];
int main()
{
SIS;
//¼ÓËÙcin/cout
for(ll i=1;i<=32000;i++)
{
b[i]=i*i;
}
int t;
cin>>t;
while(t--)
{
ll l,r;
int pos1,pos2,flag1=0,flag2=0;
cin>>l>>r;
pos1=lower_bound(b,b+32000,l)-b;
pos2=lower_bound(b,b+32000,r)-b;
if(b[pos2]==r) pos2++;
// cout<<pos1<<endl<<pos2<<endl;
cout<<pos2-pos1<<endl;
}
return 0;
}
B
dp题,首先有个抽屉原理,当元素个数>=3600时直接输出YES了。
01背包。。
啊,不会dp呀。
假如:
2000 1000 3000
一开始2000加入的时候,2000%3600=2000,便标记dp[2000]为1
下次加入1000的时候遍历dp数组一遍,会发现dp[1600]为1,便在这个基础上加上a[i]再对3600取模(这里因为只要1600被标记了故v中只加入了(1000+1600)%3600=1000),结果存储在v数组中,最后再用将v数组中存储的放入dp数组中(dp[1000]=1),在标记(1000%3600=2600)dp[2600]=1;
这样我们可以发现会大大缩小枚举范围,比如很多组合加起来%3600都为4,在下一次加入时候,我们只要计算一次便可以得出结果是多少。
#include<bits/stdc++.h>
using namespace std;
int T,m,a[100005];//用于存储初始数据
int dp[3605];
int v[10000];暂存下余数
int main()
{
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof(dp));
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=m&&!dp[0];i++)
{
int cnt=0;
for(int j=1;j<3600;j++)
{
if(dp[j])//如果发现了之前计算保留的值
{
v[cnt++]=(j+a[i])%3600;
}
}
for(int j=0;j<cnt;j++)
{
dp[v[j]]=1;
}
dp[a[i]%3600]=1;
}
if(dp[0]) printf("YES\n");
else printf("NO\n");
}
}