T1:加一
题目链接:加一 - 题目 - Daimayuan Online Judge
思路:
用f[i][j]表示数字“i”经过”j“次变换得到的位数,由于每一次都是加一操作可以得到状态转移
- i:0-8:f[i][j]=f[i+1][j-1]
- i=9:f[9][j]=f[0][j-1]+f[1][j-1];
经过预处理后,对应查询,依次输出就行了,由于本题数据很大,居然卡输入输出,只能用printf和scanf。
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+5,mod=1e9+7;
int n,f[15][MAX];
int main()
{
cin>>n;
for(int i=0;i<=9;i++)f[i][0]=1;//初始化
for(int i=1;i<=MAX;i++){
for(int j=1;j<=9;j++){
f[j][i]=f[j+1][i-1];
}
f[9][i]=(f[0][i-1]+f[1][i-1])%mod;//9+1会产生0和1两个数
}
for(int i=1;i<=n;i++){
char c[50];int k;
int ans=0;
scanf("%s %d",&c,&k);
for(int i=0;i<strlen(c);i++){
ans=(ans+f[c[i]-'0'][k])%mod;
}
printf("%d\n",ans);
}
return 0;
}
T2:跳跳
题目链接:跳跳 - 题目 - Daimayuan Online Judge
思路:
如图,我们要求的就是有多少种(A,B)的搭配使得我们可以到达给的任意一个点
显然对于A的值就是Δx1,Δx2,Δx3的最大公约数,但是这样就很难判断我们是否需要另外一个魔法,不妨将k1先算出来,求出每一组的A,B值去重,这时候伟大的set+pair出现了,set伟大的去重能力,set的大小就是我们需要的魔法数。
#include<bits/stdc++.h>
using namespace std;
int n,ans;
struct dot{
int x,y;
}d[505];
set<pair<int,int> >s;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)scanf("%d%d",&d[i].x,&d[i].y);
for(int p=1;p<=n;p++)
{
for(int q=1;q<=n;q++){
if(p==q)continue;
int x=d[q].x-d[p].x,y=d[q].y-d[p].y;
int k=__gcd(x,y);
int xx=x/k,yy=y/k;//整除会把负号干掉
//cout<<k<<"step"<<x<<' '<<y<<"pos"<<xx<<' '<<yy<<endl;
if(k<0)s.insert(make_pair(-1*xx,-1*yy));//还原负号
else s.insert(make_pair(xx,yy));
}
}
cout<<s.size()<<endl;
return 0;
}
T3:异或和或
题目链接:异或和或 - 题目 - Daimayuan Online Judge
思路:
- 异或(1和0)就能产生1,(0和0)只能产生0,(1,1)产生0
- 或:(1,0)产生1,(1,1)产生1,(0,0)产生0
由上面可以知道1对于这个序列的变化是很重要的,只要这个序列有1就可以产生0,生成任意序列,但是全是0就没办法变化
#include<bits/stdc++.h>
using namespace std;
int n;
string a[1004],b[1005];
bool check(int x){
int L=a[x].length(),cnt1_a=0,cnt1_b=0;
for(int i=0;i<L;i++){
if(a[x][i]=='1')cnt1_a++;
if(b[x][i]=='1')cnt1_b++;
}
if(cnt1_a&&cnt1_b)return 1;
else return 0;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i]>>b[i];
for(int i=1;i<=n;i++){
if(a[i]==b[i]){//如果相等直接输出YES
cout<<"YES"<<endl;continue;
}
if(a[i].length()!=b[i].length())//如果长度都不相等肯定没办法变
{
cout<<"NO"<<endl;continue;
}
if(check(i)){//检查是否有1
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
}
return 0;
}
T4:01序列
题目链接:01序列 - 题目 - Daimayuan Online Judge
思路:
由数据范围10e6首先就可以排除前缀和+双指针的做法了o(n^2),
- 首先特判一下k=0的情况,此时就需要找0子串
- 由于01序列的前缀和数组一定是单调递增(非严格),可以用一个cnt【x】这个就是前缀和sum[i]=x出现的次数,只要cnt[x+k]存在(大于0)就可以得到cnt【x】*cnt【x+k】个子串使得1出现的次数是k次
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
long long ans;
void solve(){
int n, k;
string str;
cin >> k >> str;
n = str.size();
if (k == 0) {//特判
std::vector<LL> a;
LL res = 0;
for (int i = 0; i < n; i ++) {
if (str[i] == '0')
res ++;
if (str[i] == '1' || i == n - 1) {
a.push_back(res);
res = 0;
}
}
LL ans = 0;
for (auto i : a)
ans += (i + 1) * i / 2;//1-i个子串均满足求和
cout << ans;
return ;
}
LL ans = 0;
map<LL, LL> mp;
vector<LL> sum(n + 1);
mp[0] = 1;
sum[0] = 0;
for (int i = 1; i <= n; i ++) {
sum[i] = sum[i - 1] + str[i - 1] - '0';
mp[sum[i]] ++;
}
int x = 0;
while (mp[x + k] != 0) {//由于前缀和数组单调递增,只要前面不满足,后面一定不存在
ans += mp[x] * mp[x + k];
x ++;
}
cout << ans;
}
int main()
{
solve();
return 0;
}
T5:出栈序列判断
题目链接:http://oj.daimayuan.top/course/11/problem/55
模拟模拟
#include <bits/stdc++.h>
using namespace std;
int n,t,s[100010],a[100010];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int num = 1;
for (int i = 1; i <= n; i++)
{
while (!t || s[t] != a[i])
{
printf("push %d\n", num);
s[++t] = num;
num++;
}
if (s[t] == a[i])
{
printf("pop\n");
t--;
}
}
return 0;
}
T6:序列维护
题目链接:序列维护 - 题目 - Daimayuan Online Judge
模拟
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int> v;
void Insert(int x,int y){
v.insert(v.begin()+x,y);
}
int main()
{
cin>>n;
string s;int x,y;
for(int i=1;i<=n;i++){
cin>>s;
if(s=="insert"){
cin>>x>>y;
v.insert(v.begin()+x,y);
}
else if(s=="delete"){
cin>>x;
v.erase(v.begin()+x-1);
}
else if(s=="query"){
cin>>x;
cout<<*(v.begin()+x-1)<<endl;;
}
}
return 0;
}