整数拼接
#include<iostream>
#include<string>
using namespace std;
typedef long long LL;
const int N=100010;
int s[11][N];//表示某个数*10^i%k==j的数量
int n;//表示将要输入的n个数
LL a[N];//存放n个数
int k;//表示k倍
LL res;//表示结果
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
for(int i=0;i<n;i++)
{
LL t=a[i]%k;
for(int j=0;j<11;j++)
{
s[j][t]++;//余数为t的方案增加
printf("s[%d][%d]:%d\n",j,t,s[j][t]);
t=t*10%k;//a[i]乘j个10的余数
}
}
for(int i=0;i<n;i++)
{
LL t=a[i]%k;
int len=to_string(a[i]).size();//获取a[i]位数
res+=s[len][(k-t)%k];//(k-t)%k确保得到的余数始终为非负数,并且小于 k
//找到与a[i]的余数相加能余数为0的方案,len符合
printf(" %d %d\n",len,(k-t)%k);
LL r=t;
while(len--)
{
r=r*10%k;//a[i]乘以自己长度个10的余数
}
if(r==(k-t)%k)//去除自己和自己组合的方案
{
printf("%d\n",r);
res--;
}
}
cout<<res<<endl;//4+4-2
return 0;
}
卡片(模拟)
自写
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(void){
vector<int> card(10, 2021);
int num=0;
for(int i=1;;i++){
int j=i;
while(j){
int x=j%10;
if(!card[x])goto end;
else card[x]--;
j/=10;
}
num=i;
}
end:cout<<num;
}
直线(数学)
l定义在内部,且用完要清空;保存三个参数的公约数;set和list结构
式子来自
#include<bits/stdc++.h>
using namespace std;
//最大公约数
inline int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
//点结构
struct Node{
int x;
int y;
}node[450];
//set
set<list<int> >s;
int main(void)
{
int cnt = 0;
//读入点
for(int i = 0; i < 20; i++)
for(int j = 0; j < 21; j++)
{
node[++cnt].x = i;
node[cnt].y = j;
}
//遍历点
for(int i = 0; i <= cnt; i++)
//第二个点没必要从0开始了
for(int j = i + 1; j <= cnt; j++)
{
int x1 = node[i].x, x2 = node[j].x;
int y1 = node[i].y, y2 = node[j].y;
//去掉相同点
if(x1 == x2 && y1 == y2) continue;
//系数计算
int a = y2 - y1;
int b = x1 - x2;
int c = x2 * y1 - x1 * y2;
int gcdn = gcd(a,gcd(b, c));
list<int>l;
l.push_back(a/gcdn);
l.push_back(b/gcdn);
l.push_back(c/gcdn);
s.insert(l);
}
cout <<s.size();
return 0;
}
路径(最短)
思路:建数组(每条路长度,经过与否,总路程长度),从头遍历到尾,距离i最近的点k,有没有别的路从i到k更近
注意点:初始化所有数组,单独初始与起始点有关的数组
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MAXN 1e18
//边数组
ll edge[2025][2025], n = 2021;
//最短路数组,前驱数组
ll dist[2025], pre[2025];
//标记数组
bool vis[2025];
void Dijkstra()
{
//初始化
for(int i = 1; i <= n; i++){
vis[i] = false;
dist[i] = edge[1][i];
if(edge[1][i] < MAXN){
pre[i] = 1;
}
}
//标记
vis[1] = true; dist[1] = 0;
//n-1趟循环
for(int i = 1; i < n; i++){
//找出所有未访问的点中距离起点最近的点
int temp;
ll minn = MAXN;
for(int j = 1; j <= n; j++){
if(!vis[j] && dist[j] < minn){
minn = dist[j];
temp = j;
}
}
vis[temp] = true;
//以temp为中间点,刷新起点到各点的最短路径
for(int j = 1; j <= n; j++){
if((dist[temp]+edge[temp][j] < dist[j]) && !vis[j]){
dist[j] = dist[temp]+edge[temp][j];
pre[j] = temp;
}
}
}
}
int main(void)
{
//边权值读入
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(i == j) edge[i][j] = 0;
else if(abs(i - j) <= 21) edge[i][j] = edge[j][i] = i * j / __gcd(i, j);
else edge[i][j] = edge[j][i] = MAXN;
}
}
Dijkstra();
printf("%lld", dist[2021]);
return 0;
}
砝码问题
比如有abc三物品,依次产生的重量为a,a+b,b,a+b+c,a+c或b+c,c
#include <bits/stdc++.h>
using namespace std;
int w[101], n;
int dp[100010];
int main(void)
{
//cin
cin >>n;
for(int i = 1; i <= n; i++) cin >>w[i];
memset(dp, 0, sizeof(dp));
dp[0] = 1;
//第一次01背包(加 | 不加)
for(int i = 1; i <= n; i++)
for(int j = 100000; j >= w[i]; j--){
dp[j] = max(dp[j], dp[j - w[i]]);//dp[j - w[i]]已经有了方案,才会更新dp[j]
}
//二次dp(减状态)
for(int i = 1; i <= n; i++)
for(int j = 0; j <= 100000 - w[i]; j++)
dp[j] = max(dp[j], dp[j + w[i]]);
//结果计数
long long res = 0;
for(int i = 0; i <= 100000; i++)
res += dp[i];
cout <<res - 1;
return 0;
}