1.进制转换

2.顺子日期

3.刷题统计

#include<iostream>
using namespace std;
#define ll long long
int main()
{
ll a, b, n;
cin >> a >> b >> n;
ll week = a * 5 + b * 2;
ll ans = n / week * 7;
n %= week;
for (int i = 1; i <= 5; i++)
{
if (n > 0)
n -= a, ans++;
}
for (int i = 1; i <= 2; i++)
{
if (n > 0)
n -= b, ans++;
}
cout << ans << endl;
//system("pause");
return 0;
}
4.修剪灌木

#include<iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int t = n * 2 - 2;
for (int i = 1; i <= n / 2; i++)
{
cout << t << endl;
t -= 2;
}
if ((n & 1) == 0)
t += 2;
for (int i = n / 2 + 1; i <= n; i++)
{
cout << t << endl;
t += 2;
}
//system("pause");
return 0;
}
5.X进制减法
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 1e6 + 7;
const int mod = 1000000007;
int n, m;
int a[N], b[N];
int main()
{
scanf("%d%d", &n, &n);
for (int i = n; i; i--)
scanf("%d", a + i);
scanf("%d", &m);
for (int i = m; i; i--)
scanf("%d", b + i);
long long ans = 0;
for (int i = n; i; i--)
{
ans = ans * max(2, max(a[i] + 1, b[i] + 1)) % mod;
ans = ((ans + a[i] - b[i]) % mod + mod) % mod;
}
printf("%lld\n", ans);
//system("pause");
return 0;
}
6.统计子矩阵

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 500 + 7;
int n, m;
int k;
int a[N][N];
int s[N][N];
signed main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
scanf("%d", &a[i][j]);
s[i][j] = s[i - 1][j] + a[i][j];
}
}
long long ans = 0;
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j++)
{
for (int l = 1, r = 1, sum = 0; r <= m; r++)
{
sum += s[j][r] - s[i - 1][r];
while (sum > k)
sum -= s[j][l] - s[i - 1][l++];
ans += r - l + 1;
}
}
}
printf("%lld\n", ans);
//system("pause");
return 0;
}
思路:枚举 起始行 和 行数 ,然后遍历列,得到了一个长度为 m 的一维的数组,在这个数组中用双指针优化。
7.积木画

//状压DP
#include<iostream>
using namespace std;
const int mod = 1e9 + 10;
int n;
long long dp[2][4], l, now = 1;
int main()
{
cin >> n;
dp[l][3] = 2;
dp[l][0] = dp[l][1] = dp[l][2] = 1;
while (--n)
{
dp[now][0] = dp[l][3];
dp[now][1] = (dp[l][0] + dp[l][2]) % mod;
dp[now][2] = (dp[l][0] + dp[l][1]) % mod;
dp[now][3] = (dp[l][0] + dp[l][2] + dp[l][1] + dp[l][3]) % mod;
swap(l, now);
}
cout << dp[l][0] << endl;
//system("pause");
return 0;
}
思路:
状压:
dp[now][0]代表当前列刚好填满
dp[ now ][1]代表当前列填满并向下一列突出了上面的一格
dp[now][2] 代表当前列填满并向下一列突出了下面的一格
dp[now][3] 代表当前列填满并向下一列突出两格。
dp[la]代表上一列
状态转移:
当前列填满:上一列填满并向下一列(当前列)填两格。
当前列填满并上凸一格:上一列填满加上上一列填满并下凸。
当前列填满并下凸一格:上一列填满加上上一列填满并上凸。
当前列填满并向下一列突出两格:所有情况相加。
8.扫雷
(可恶的卡常)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <unordered_map>
using namespace std;
const int maxn=50010;
struct Node
{
int x,y,r;
int cnt;
Node (int _x,int _y) : x(_x),y(_y){}
Node (int _x,int _y,int _r) : x(_x),y(_y),r(_r){}
Node (int _x,int _y,int _r,int _cnt) :x(_x),y(_y),r(_r),cnt(_cnt){}
Node()=default;
bool operator < (Node const & a) const
{
if(x!=a.x)
return x<a.x;
return y<a.y;
}
}cir[maxn];
struct comp
{
int operator()(const std::pair<int, int>& p) const {
return p.first ^ p.second; //返回值为bool,比较符为&,|都比这一个慢,
}
};
typedef long long LL;
LL squ(int x)
{
return (LL) x*x;
}
vector<int> adj[maxn];
unordered_map<pair<int,int> ,int,comp> ump;
bool vis[maxn]={false};
int n,m;
int dfs_Trave(int x,int y,int r);
int dfs(int index);
void add(int index);
int main()
{
scanf("%d%d",&n,&m);
int x,y,r;
for(int i=1;i<=n;++i)
{
scanf("%d%d%d",&x,&y,&r);
auto temp=ump[{x,y}];
if(temp!=0)
{
cir[temp].r=max(cir[temp].r,r);
cir[temp].cnt++;
}
else
{
cir[i]={x,y,r,1};
ump[{x,y}]=i;
}
}
sort(cir+1,cir+n+1);
for(int i=1;i<=n;++i)
{
add(i);
}
int res=0;
for(int i=0;i<m;++i)
{
scanf("%d%d%d",&x,&y,&r);
res+=dfs_Trave(x,y,r);
}
printf("%d\n",res);
system("pause");
return 0;
}
void add(int index)
{
for(int i=index-1;i>0;--i)
{
if(squ(cir[index].r)<squ(cir[i].x-cir[index].x))
break;
if(squ(cir[index].r)>=squ(cir[i].x-cir[index].x)+squ(cir[i].y-cir[index].y))
adj[index].push_back(i);
}
for(int i=index+1;i<=n;++i)
{
if(squ(cir[index].r) < squ(cir[i].x-cir[index].x))
break;
if(squ(cir[index].r) >= squ(cir[i].x-cir[index].x)+squ(cir[i].y-cir[index].y))
adj[index].push_back(i);
}
}
int dfs(int index)
{
int sum=cir[index].cnt;
vis[index]=1;
for(int i=0;i<adj[index].size();++i)
{
int v=adj[index][i];
if(vis[v]==0)
sum+=dfs(v);
}
return sum;
}
int dfs_Trave(int x,int y,int r)
{
Node e1={x-r,y,r},e2={x+r,y,r};
int l=lower_bound(cir+1,cir+n+1,e1)-cir;
int ri=lower_bound(cir+1,cir+n+1,e2)-cir;
l=min(l,n),ri=min(ri,n);
int sum=0;
for(int i=l;i<=ri;++i)
{
if(i==0)
continue;
if((squ(r)>=squ(cir[i].x-x)+squ(cir[i].y-y))&&vis[i]==0)
sum+=dfs(i);
}
return sum;
}
思路:转换成有向图的遍历问题,(在爆炸范围内就建一条单边,遍历有向图,判断点上有没有雷),要用哈希。
9.李白打酒加强版

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
const int mod = 1e9 + 7;
ll dp[110][110][110];
int t;
int main()
{
cin>>t;
while(t--){
int n, m;
scanf("%d%d", &n, &m);
dp[n][m][2] = 1;
for (int i = n; i >= 0; i--)
{
for (int j = m; j >= 0; j--)
{
for (int k = 0; k <= m; k++)
{
if (i && k*2 <= m)
dp[i - 1][j][k*2] = (dp[i - 1][j][k*2] + dp[i][j][k]) % mod;
if (k && j)
dp[i][j - 1][k - 1] = (dp[i][j - 1][k - 1] + dp[i][j][k]) % mod;
}
}
}
printf("%lld\n", dp[0][1][1]);
for(int i=0;i<110;i++)
for(int j=0;j<110;j++)
for(int k=0;k<110;k++)
dp[i][j][k] = 0;
}
//system("pause");
return 0;
}
思路:dp
状态表示:
dp[i][j][k]代表 有 i 家店没有遇到,j 朵花没有看,壶中有 k 斗酒的方案数.
转移方程:
if (i && k2 <= m)
dp[i - 1][j][k2] = (dp[i - 1][j][k*2] + dp[i][j][k]) % mod;
if (k && j)
dp[i][j - 1][k - 1] = (dp[i][j - 1][k - 1] + dp[i][j][k]) % mod;
10.砍竹子

#include<iostream>
#include<cmath>
#include<cstdio>
#include<vector>
using namespace std;
long long msq(long long x) // 手写开根
{
long long r = sqrt(x) + 10;
for (long long i = max(0ll, r - 20); i <= r; i++)
{
if (i * i > x)
return i - 1;
}
return r - 10;
}
int main()
{
int n;
scanf("%d", &n);
vector<long long> v[2];
int now = 0, la = 1;
long long ans = 0;
while (n--)
{
long long t;
scanf("%lld", &t);
v[now].clear();
while (t > 1)
{
v[now].push_back(t);
t = msq(t / 2 + 1);
}
ans += v[now].size();
for (int i = 0; i < v[now].size(); i++)
{
for (int j = 0; j < v[la].size(); j++)
{
if (v[now][i] == v[la][j])
{
ans -= v[now].size() - i;
goto g;
}
}
}
g:
swap(now, la);
}
printf("%lld\n", ans);
//system("pause");
return 0;
}
思路:贪心,枚举
核心结论:使用魔法来砍所减少的次数就是每对相邻竹子的公共的路程 , 枚举每个相邻的竹子所到的点即可
7万+

被折叠的 条评论
为什么被折叠?



