题意
有一个字符串 和一个数k
改变最少的字符使得字符串的前k个字符与后k个字符 相同
思路
使用并查集,将需要相同的字符并起来。再在每个集合中将其修改为出现次数最多的字符。
#include
using namespace std;
int f[10000],vis[100010];
map<char,int>num;
class NewArenaPassword {
public:## 标题
int minChange( string oldPassword, int K );
};
int NewArenaPassword::minChange(string a, int k) {
int i,n,j,ans=0,x;
n=a.size();
memset(vis,0,sizeof(vis));
memset(f,-1,sizeof(f));
if(n==k) return 0;
for(i=0;i<k;i++) f[i+n-k]=i;
for(i=n;i>=0;i--)
{
if(vis[i]==0)
{
num.clear();
x=0;
int temp=0;
j=i;
while(j!=-1)
{
vis[j]=1;
x++;
num[a[j]]++;
temp=max(temp,num[a[j]]);
j=f[j];
}
ans+=(x-temp);
}
}
return ans;
}
题意
给出n个字符串组p 和 一个数组a
a[i]表示p[i]串中有a[i]个位置与正确的串相同
判断 输出 正确的串
如有多个答案 输出 Ambiguity
如没有答案 输出 Liar
思路
使用中途相遇法。
将数字拆成前后两半,枚举前一半,算出每次猜测的猜对位数,放入map中,再枚举后一半,算出互补的前一半猜对位数,在map中查询。
#include
using namespace std;
class EllysBulls {
public:
string getNumber( vector <string> guesses, vector <int> bulls );
};
inline string work(int a,int l)
{
string s(l,'0');
for(int i=1;a;i++)
{
s[l-i]=a%10+'0';
a=a/10;
}
return s;
}
inline int sol(const string &x,const string &y)
{
int ans=0,i;
for(i=0;i<x.size();i++) ans+=(x[i]==y[i]);
return ans;
}
string EllysBulls::getNumber(vector <string> a, vector <int> b) {
int i,j,t=1,n,m,l,r,x;
string s,ans="Liar";
n=a.size();
m=a[0].size();
l=m>>1;
r=m-l;
vector<int> d(n);
map<vector<int>,int> h;
for(i=0;i<l;i++) t=t*10;
for(i=0;i<t;i++)
{
s=work(i,l);
for(j=0;j<n;j++)
d[j]=sol(s,a[j].substr(0,l));
if(h.count(d)) h[d]=-1;
else h[d]=i;
}
t=1;
for(i=1;i<=r;i++) t=t*10;
for(i=0;i<t;i++)
{
s=work(i,r);
for(j=0;j<n;j++)
d[j]=b[j]-sol(s,a[j].substr(l));
if(h.count(d))
{
x=h[d];
if(x==-1||ans!="Liar") return "Ambiguity";
ans=work(x,l)+s;
}
}
return ans;
}
题意
n=s[1]+s[2]+…+s[k];
s序列的每一个数对于m的余数不同
k可以为任意数
问有多少个s序列
思路:
有点类似0/1背包,每个剩余类只能选一个,可以用f[i][j]表示i个在[0,M−1]的数和为j的方案数,DP一波。
对于f[i][j],若j≡N(mod M)且j<=N,则对答案的贡献为
f[i][j]∗C((N−j)/M+i−1,i−1)∗i
考虑给每个数加上m的整数倍之后模m不会发生变化,所以肯定还是符合模m两两互不相同,然而和却神不知鬼不觉地增大了。所以要使总和为N就相当于把(N−j)/M个M分给i个数,套用经典的小球模型就是把(N−j)/M个小球分给i个盒子,可以为空,这个方案数是C((N−j)/M+i−1,i−1),题目里是有序的,所以还要乘个阶乘。
为方便计算,上式进一步简化就是f[i][j]∗A((N−j)/M+i−1,i−1)∗i
#include
using namespace std;
const int mod=1e9+7;
long long d[100][2510];
class DistinctRemainders {
public:
int howMany( long long N, int M );
};
long long sol(long long x,long long y)
{
if(x<y) return 0;
long long s=1;
for(int i=1;i<=y;i++)
s=(s*((x-i+1)%mod))%mod;
return s;
}
int DistinctRemainders::howMany(long long n, int m) {
int i,tot=0,k;
long long ans=0;
d[0][0]=1;
for(i=0;i<m;i++)
{
tot+=i;
for(int j=i+1;j>0;j--)
for(k=i;k<=tot;k++)
d[j][k]=(d[j][k]+d[j-1][k-i])%mod;
}
for(i=1;i<=m;i++)
for(long long j=n%m;j<=n&&j<=tot;j+=m)
ans=(ans+d[i][j]*sol((n-j)/m+i-1,i-1)%mod*i%mod)%mod;
return (int)ans;
}